Java 类及类的成员
属性、方法、构造器、代码块、内部类
面向对象的三大特征
封装、继承、多态、(抽象性)
其他关键字:this,super,final,static,abstract,interface,package,import
面向过程(POP)【Procedure Oridented Programming】与面向对象(OOP)【Object Oriented Programming】:
1.二者都是一种思想,面向对象是相对于面向过程而言的。
面向过程,强调的是功能行为,以函数为最小单位。考虑怎么做。
面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
2.面向对象更加强调运用人类在日常思维逻辑中采用的思想方法与原则,如抽象、分类、继承、聚合、多态等。
面向对象的三大特征:
1.封装
2.继承
3.多态
Java 语言的基本元素:
类和对象
类:是对一类事物的描述,是抽象的、概念上的定义
对象:是实际存在的该类事物的每个个体,也称为实例。
面向对象程序设计的重点:类的设计(设计类:就是设计类的成员(成员变量(属性),成员方法(函数/方法)))。
对象内存解析:
栈:地址,局部变量
堆:属性,方法,对象。
匿名对象。
方法的重载:
概念:
在同一个类中,允许存在一个以上的同名方法,只要他们的参数个数或者参数类型不同即可。
特点:
与返回值类型无关,只看参数列表,且参数列表必须不同(参数个数或参数类型)。调用时,根据方法参数列表的不同来区别。
可变个数的形参
格式:数据类型 ... 变量名
方法参数的值传递机制:
Java 里方法的参数传递方式只有一种:值传递。即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响。
1.形参是基本数据类型:而实参基本数据类型变量的"数据值"传递给形参
2.形参是引用数据类型:将实参引用数据类型变量的"地址值"传递给形参
如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。
方法中定义的变量属于局部变量,存储在栈中。
变量的赋值:
1.如果变量是基本数据类型,此时赋值的变量所保存的是数据值。
2.如果变量是引用数据类型,此时赋值的变量所保存的数据是地址值。
方法的执行过程就是栈的出入栈的过程。
方法的递归调用
封装性:
封装性的设计思想:把该隐藏的隐藏起来,该暴露的暴露出来。
封装性的体现:
将类的属性私有化private,提供公共的 public 方法来获取 getXxx和设置此属性 setXxx.
构造器:
作用:创建对象、初始化对象结构
UML 类图:
this关键字:
this 可以用来修饰:属性、方法、构造器
this 修饰属性和方法:
this 理解为:当前对象,当前正在创建的对象。
this 调用构造器:
1.在类的构造器中,可以显式使用 "this(形参列表)"方式,调用指定的类的其他构造器。
2.构造器中不能通过"this(形参列表)"方式调用自己。
3.如果一个类中有 n 个构造器,则最多有 n-1 构造器中使用了"this(形参列表)"
4.规定:"this(形参列表)"必须声明在当前构造器的首行
5.构造器内部,最多只能声明一个"this(形参列表)",用来调用其他构造器
package:
import:
MVC设计模式:视图模型层、控制器层、数据模型层。
继承性:
好处:
1.减少了代码的冗余,提高了代码的复用性。
2.便于功能的扩展
3.为之后多态性的使用,提拱了前提。
继承性的格式: class A extends B{}
A:子类、派生类、subclass
B:父类、超类、基类、superclass
体现:
一旦子类A继承了父类B以后,子类A中就获取了父类B中声明的所有的属性和方法。
特别的,父类中声明为 private 的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。
只是因为封装性的影响,使得子类不能直接调用父类的结构而已。
子类继承父类后,还可以声明自己特有的属性或方法:实现功能的扩展。
Java 只支持单继承和多层继承,不允许多重继承
一个子类只能继承一个父类
一个父类可以派生出多个子类。
所有的Java类(除java.lang.Object类之外)都直接或间接的继承于java.lang.Object类。
方法的重写:
理解:override、overwrite
在子类中可以根据需要对从父类中继承来的方法进行改造,也称为方法的重置、覆盖。在程序执行时,
子类的方法将覆盖父类的方法。
要求:
1.子类重写的方法必须和父类被重写的方法具有相同的方法名称、参数列表
2.子类重写的方法的返回值类型不能大于父类被重写的方法的返回值类型。
3.子类重写的方法使用的访问权限不能小于父类被重写的方法的访问权限
子类不能重写父类中声明为 private 权限的方法。
4.子类方法抛出的异常不能大于父类被重写方法的异常
注意:
子类与父类中同名同参数的方法必须同时声明为非 static 的(即为重写),或者同时声明为 static的(不是重写)。
因为 static 方法属于类的,子类无法覆盖父类的方法。
3W:what? why? how?
多态性:
Java 中体现:
理解:
一个事物的多种形态。
对象的多态性:父类的引用指向子类的对象
可以直接应用在抽象类和接口上
使用:
在调用子父类同名同参数的方法时,实际执行的是子类重写父类的方法 —— 虚拟方法调用。
使用前提:
1.类的继承关系
2.方法的重写
多态性只适用于方法,不适用属性。
Java 引用变量有两个类型:编译时类型和运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量
的对象决定。简称:编译时,看左边;运行时,看右边。
若编译时类型和运行时类型不一致,就出现了对象的多态性。
多态情况下,"看左边":看的是父类的引用(父类中不具备子类持有的方法)。
"看右边":看的是子类的对象(实际运行的是子类重写父类的方法)。
虚拟方法调用:
子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,动态调用属于子类
的该方法。这样的方法调用在编译期是无法确定的。
instanceof 操作符:
x instanceof A : 检验 X 是否为 A 的对象,返回值为 boolean 型。
使用场景:
为了避免在向下转型时出现 ClassCastException 异常,在向下转型之前,先进行 instanceof 判断。
向下转型:
使用强制类型转换符。父类向子类。
向上转型:
多态:子类向父类。
== :
对于引用数据类型来讲,比较的是两个引用数据类型变量的地址是否相同。
对于基本数据类型来讲,比较两个变量保存的数据是否相等。(不一定类型要相同)
面试题:
多态是编译时行为还是运行时行为?
如何证明?
解决方法:
多态是运行时行为。
Object 类的使用:
是所有 Java 类的根父类。
面试题:
final(关键字)、finally(关键字)、finalize(方法名) 的区别?
finalize():当前对象被回收时会调用 finalize() 方法。
equals() :
1.只能适用于引用数据类型
2.重写的原则:比较两个对象的实体内容是否相同。
== 和 equals() 的区别:
1. == 既可以比较基本类型也可以比较引用数据类型。对于基本数据类型,比较数据值,对于引用数据类型就是比较内存地址。
2.equals(),是属于 java.lang.Object 类里面的方法,如果该方法没有被重写过默认也是 ==;我们可以看到 String 等
类的 equals 方法是被重写过的,而且 String 类在日常开发中用的比较多,久而久之,形成了 equals 是比较值的
错误观点。
3.具体要看自定义类型里有没有重写 Object 的 equals 方法来判断。
4.通常情况下,重写 equals 方法,会比较类中的相应属性是否都相等。
包装类的使用:
包装类:
针对八种基本数据类型定义相应的引用数据类型 —— 包装类(封装类)。
有了类的特点,就可以调用类中的方法,Java 才是真正的面向对象。
基本数据类型与包装类之间的转换:
包装类 ——> 基本数据类型:调用包装类的 Xxx 的 xxxValue() 方法
基本数据类型 ——> 包装类:调用包装类的构造器。
自动装箱:基本数据类型 ——> 包装类
自动拆箱:包装类 ——> 基本数据类型
String ——> 基本数据类型、包装类:调用包装类的 parstXxx()
基本数据类型、包装类 ——> String : 调用 String 重载的 valueOf(Xxx xxx) 方法。
Ojbect o1 = true ? new Integer(1) : new Double(2.0);
System.out.println(o1); //1.0:三元运算符 ? 后表达式的类型要相同。Integer 自动提升到 Double.
public void test() {
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j); //false
Integer i = 1;
Integer j = 1;
System.out.println(i == j); //true
Integer i = 128;
Integer j = 128;
System.out.println(i == j); //false, 超限(缓存最大127),128 = new Integer(128);
}
static 关键字:
静态的
可以用来修饰:
属性:静态变量。
静态变量 VS 非静态变量(实例变量)
静态变量随着类的加载而加载。
静态变量的加载要早于对象的创建。
由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法的静态域中。
方法:静态方法。
随着类的加载而加载,可以通过"类.静态方法"的方式进行调用
代码块:
内部类:
开发中,如何确定一个属性是否要声明为 static 的?
1.属性是可以被多个对象所共享的,不会随着对象的不同而不同。
2.类中的常量也常常声明为 static.
开发中,如何确定一个方法是否要声明为 static 的?
1.操作静态属性的方法,通常设置为 static 的。
2.工具类中的方法,习惯上声明为 static 的。
单例(Singleton)设计模式:
1.设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。
2.在整个的软件系统中,对某个类只能存在一个对象实例。
3.区分 饿汉式 和 懒汉式 ?
饿汉式:
坏处:对象加载时间过长。
好处:饿汉式是线程安全的。
懒汉式:
好处:延迟对象的创建。
坏处:懒汉式是线程不安全的。
4.优点
由于单例设计模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、
产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方法来解决。
例如:java.lang.Runtime
5.单例设计模式应用场景:
1.网站的计数器:一般也是单例模式实现,否则难以同步
2.应用程序的日志应用,一般都使用单例模式实现,这一般都是由于共享的日志文件一直处于打开状态,因为只能有一个
实例去操作,否则内容不好追加。
3.数据库连接池的设计一般也是采用单例设计模式,因为数据库连接是一种数据库的资源。。
4.项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,都生成一个对象去读取。
5.Application 也是单例的典型应用
6.windows 的 Task Manager(任务管理器)就是很典型的单例模式。
7.windows 的 Recycle Bin 也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
代码块:
作用:用来初始化类、对象。
代码块如果有修饰的话,只能使用 static.
静态代码块 VS 非静态代码块
静态代码块:
1.内部可以有输出语句
2.随着类的加载而执行,且只执行一次
3.初始化类的属性。
4.如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行。
5.静态代码块的执行要优先于非静态代码块的执行。
6.静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构。
非静态代码块:
1.内部可以有输出语句
2.随着对象的创建而执行
3.每创建一个对象,就执行一次非静态代码块
4.作用:可以在创建对象时,对对象的属性等进行初始化。
5.如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行。
对属性的赋值:
1.默认初始化
2.显式初始化
3.构造器中初始化
4.有了对象以后,可以通过"对象.属性"或"对象.方法"的方式,进行赋值。
执行顺序:1 ——> 2/5 ——> 3 ——> 4
final 关键字:
1.可以用来修饰的结构:类、方法、变量
2.final 用来修饰一个类:此类不能被其他类所继承。比如 String,System.等
3.fianl 用来修饰一个方法:表明此方法不能被重写。
4.final 用来修饰变量:此时的"变量"就称为是一个常量
final 修饰属性:可以考虑赋值的方式有:显式初始化、代码块中初始化、构造器中初始化。
final 修饰局部变量:
使用 final 修饰形参时,表示此形参时一个常量。当我们调用此方法时,给常量形参赋
一个实参.初始化以后,就只能在方法体内使用此形参,但不能进行重新赋值。
static fianl 用来修饰属性:全局常量
抽象类与抽象方法:
abstract:
修饰类:
1.不能实例化。
2.抽象类中一定有构造器,便于子类对象实例化的时候调用。
3.开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作。
方法:
1.抽象方法只有方法的声明,没有方法体。
2.包含抽象方法的类,一定是一个抽象类。反之,抽象类中是可以没有抽象方法的。
3.若子类重写了父类中的所有的抽象方法后,此子类方可实例化。
若子类没有重写了父类中的所有的抽象方法后, 则次子类也是一个抽象类,需要使用 abstract 进行修饰。
应用:
抽象类是用来模型化那些父类无法确定全部实现,而是由其子类提供具体实现的对象的类。
注意点:
1.abstract 不能用来修饰:属性、构造器等结构
2.abstract 不能用来修饰私有方法、静态方法、final 方法。
多态的应用:模板方法设计模式(TemplateMethod)
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行
扩展、改造,但子类总体上会保留抽象类的行为方式。
解决的问题:
1.当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
2.换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分
易变,易变部分可以抽象出来,供不同的子类实现。这就是一种模板模式。
接口:
接口就是规范,定义的是一组规则,体现了现实世界中"如果你是/要...则必须能..."的思想。继承是一个"是不是"的关系,而接口
实现则是"能不能"的关系。
接口的本质是契约,标准,规范。
有了接口,就可以得到多重继承的效果(Java 不支持多继承)。
接口中不能定义构造器的!意味着接口不可以实例化。
Java 开发中,接口通过让类去实现(implements)的方式来使用。
如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化。
如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类。
Java 类可以实现多个接口 ————> 弥补了 Java 单继承的局限性。
接口与接口之间可以继承,而且可以多继承。
接口的具体使用,体现多态性。
接口,实际上可以看做是一种规范。
面试题:
抽象类与接口有哪些异同?
接口的应用:代理模式(Proxy)
概述:代理设计就是为其他对象提供一种代理以控制对这个对象的访问。
内部类:
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,
那么整个内部的完整结构最好使用内部类。
允许一个类的定义位于另一个类的内部,称为内部类。
分类:
成员内部类(静态、非静态) VS 局部内部类(方法内、代码块内、构造器内)
成员内部类:
1.作为外部类的成员
调用外部类的结构。
可以被 static 修饰。
可以被4种不同的权限修饰。
2.作为一个类:
类中可以定义属性、方法、构造器等。
可以被 final 修饰,表示此类不能被继承。
可以被 abstract 修饰。
1.实例化成员内部类的对象
2.在成员内部类中区分调用外部类的结构
3.开发中局部内部类的使用
来源:https://blog.csdn.net/weixin_45558989/article/details/101264071