学习总结(2022.03.31-2022.04.06)
继承的限制
- 子类不可以继承父类的私有成员,因为没有访问权限。
- 子类不可以继承父类的构造器,因为构造器不能算成员。
- 子类可以访问父类的静态方法,但是并不是继承。
继承中的属性隐藏和方法覆盖
对于成员变量的访问范围和访问结果都看引用类型。引用是父类则访问的是父类成员变量,子类则访问子类成员变量。
对于成员方法的访问范围如上相同,看引用类型。
对于成员方法的访问结果则看对象类型。对象是子类则可以调用子类方法、重写或没重写的父类方法,父类则只能调用父类方法。
final关键字
final修饰类表示类不可被继承。
final修饰方法表示方法不可被重写,但可以被继承。
final修饰变量表示常量。与static一起用表示全局变量。
instanceof关键字
用来判断一个类是否是某个类的子类,一般用于保证向下转型的安全。
抽象类(abstract)
抽象类与普通类相同,但是多了一个抽象方法,即不需要实现该方法,而是让子类通过重写的方式来实现。抽象类和抽象类之间可以有继承关系,且继承的抽象类可以选择重写被继承抽象类的抽象方法。
接口(interface)
接口是一种开发标准,表示对功能的扩展,只关注行为而不关注属性。一般用来抽象共性行为,与实现其的类为like-a关系。
接口不能创建对象,自然也没有构造器。
接口一般没有成员,只有抽象方法。
接口可以继承接口,但是接口和类之间不能发生继承,类只能实现(implement)接口。
内部类
- 成员内部类:与普通类相同,但是没有静态声明(允许有静态全局常量);可以发生继承和实现;与外围类有强依赖关系,可以无视访问权限互相访问。
- 静态内部类:与普通类完全相同;可以发生继承和实现;与外围类为互相独立的关系,虽然访问不受访问权限限制,但是需要创建对象才可以访问。
- 局部内部类:不具有访问修饰权限;不具有静态声明;可以发生继承和实现;虽然可以访问外部类的成员,但是外部类无法访问局部内部类的成员。
Lambda表达式
Lambda表达式是一种特殊的局部匿名内部类。必须在一个实现了功能接口(有且只有一个必须实现的抽象方法的接口)的类中定义。得到的是这个接口的子类对象。基本格式为:
1 | |
()中是抽象方法的形参列表。
{}中是抽象方法的实现。
在写完Lambda表达式后,需要在表达式前面用(对象名)帮编译器明确对象类型。
Lambda表达式可以简化:当形参只有一个时,可以省略();当方法体只有一条语句时(包括return语句),可以省略{}。
Lambda表达式的应用:将一个String对象数组映射为所有字符串长度的数组。
1 | |
Object.toString()
toString()直接使用是打印对象的全限定类名 + @ + 对象的十六进制地址值。
可以通过重写来展示对象的状态。
Object.equals()和Object.hashcode()
equals()直接使用是比较两个引用是否指向相同对象,可以通过重写来修改判断的条件(比如从比较对象的地址修改为比较对象的状态)。
重写遵从闭包原则,即
自反性。
x.equals(x) == true排他性。当比对的不是同种类型的对象或者是一个null时,默认返回false。
对称性。
x.equals(y) == true->y.equals(x) == true。传递性。
x.equals(y) == true && y.equals(z) == true->x.equals(z) == true。
其中自反性和排它性需要写代码做判断,而对称性,一致性,传递性,只需要用成员变量的取值来判断对象相等,就自动满足它们。
排他性的选择:getClass()(只能是相同的对象),instanceof(可以是对象的子类)
如果重写equals(),hashcode()也需要重写。因为逻辑上相等的两个对象必须有相同的hash值。
Object.clone()
作用是获得一个独立的,与原对象成员一致的新对象。但是在默认的情况下,只能在子类内克隆自己,所以一般需要在类中重写该方法。其次,一个类想实现克隆,需要实现一个标记接口(不含任何抽象方法的接口)java.lang.Cloneable。
浅克隆:如果克隆的类中有引用类型变量,在克隆后该变量会与克隆前的类中的变量指向同一个对象,这样并不能说明这两个类是独立的,这叫做浅克隆。
深度克隆:在clone()中做出如下操作:
- 将引用指向的对象,也克隆一份。
- 然后让克隆后的引用指向它。
可以让克隆后的引用类型变量指向一个同样被克隆的新的对象,这样就实现了深度克隆。
示例代码:
1 | |