Ykuri98
文章46
标签14
分类1
学习总结(2022.03.31-2022.04.06)

学习总结(2022.03.31-2022.04.06)

继承的限制

  1. 子类不可以继承父类的私有成员,因为没有访问权限。
  2. 子类不可以继承父类的构造器,因为构造器不能算成员。
  3. 子类可以访问父类的静态方法,但是并不是继承。

继承中的属性隐藏和方法覆盖

对于成员变量的访问范围和访问结果都看引用类型。引用是父类则访问的是父类成员变量,子类则访问子类成员变量。

对于成员方法的访问范围如上相同,看引用类型。

对于成员方法的访问结果则看对象类型。对象是子类则可以调用子类方法、重写或没重写的父类方法,父类则只能调用父类方法。

final关键字

final修饰类表示类不可被继承。

final修饰方法表示方法不可被重写,但可以被继承。

final修饰变量表示常量。与static一起用表示全局变量。

instanceof关键字

用来判断一个类是否是某个类的子类,一般用于保证向下转型的安全。

抽象类(abstract)

抽象类与普通类相同,但是多了一个抽象方法,即不需要实现该方法,而是让子类通过重写的方式来实现。抽象类和抽象类之间可以有继承关系,且继承的抽象类可以选择重写被继承抽象类的抽象方法。

接口(interface)

接口是一种开发标准,表示对功能的扩展,只关注行为而不关注属性。一般用来抽象共性行为,与实现其的类为like-a关系。

接口不能创建对象,自然也没有构造器。

接口一般没有成员,只有抽象方法。

接口可以继承接口,但是接口和类之间不能发生继承,类只能实现(implement)接口。

内部类

  1. 成员内部类:与普通类相同,但是没有静态声明(允许有静态全局常量);可以发生继承和实现;与外围类有强依赖关系,可以无视访问权限互相访问。
  2. 静态内部类:与普通类完全相同;可以发生继承和实现;与外围类为互相独立的关系,虽然访问不受访问权限限制,但是需要创建对象才可以访问。
  3. 局部内部类:不具有访问修饰权限;不具有静态声明;可以发生继承和实现;虽然可以访问外部类的成员,但是外部类无法访问局部内部类的成员。

Lambda表达式

Lambda表达式是一种特殊的局部匿名内部类。必须在一个实现了功能接口(有且只有一个必须实现的抽象方法的接口)的类中定义。得到的是这个接口的子类对象。基本格式为:

1
2
3
(形参列表) -> {
// 方法体
}

()中是抽象方法的形参列表。

{}中是抽象方法的实现。

在写完Lambda表达式后,需要在表达式前面用(对象名)帮编译器明确对象类型。

Lambda表达式可以简化:当形参只有一个时,可以省略();当方法体只有一条语句时(包括return语句),可以省略{}。

Lambda表达式的应用:将一个String对象数组映射为所有字符串长度的数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* @author yzw
* @since 2022/04/02
*/

public class HomeworkImpl {
public static void main(String[] args) {
String[] s = {"aaa","bb","c"};// 实验数组
int[] sLength = mappingObjectLength(s,o -> new int[s.length]);// mapping返回int数组
for(int i : sLength){
System.out.println(i);
}

}

public static int[] mappingObjectLength(Object[] obj, Map map){
int[] result = map.mapping(obj);
for (int i = 0; i < obj.length; i++) {
result[i] = obj[i].toString().length();
}
return result;
}
}

interface Map{
int[] mapping(Object o); //返回一个int数组表示每个元素的长度

Object.toString()

toString()直接使用是打印对象的全限定类名 + @ + 对象的十六进制地址值

可以通过重写来展示对象的状态。

Object.equals()Object.hashcode()

equals()直接使用是比较两个引用是否指向相同对象,可以通过重写来修改判断的条件(比如从比较对象的地址修改为比较对象的状态)。

重写遵从闭包原则,即

  1. 自反性。x.equals(x) == true

  2. 排他性。当比对的不是同种类型的对象或者是一个null时,默认返回false。

  3. 对称性。x.equals(y) == true -> y.equals(x) == true

  4. 传递性。x.equals(y) == true && y.equals(z) == true -> x.equals(z) == true

其中自反性和排它性需要写代码做判断,而对称性,一致性,传递性,只需要用成员变量的取值来判断对象相等,就自动满足它们。

排他性的选择:getClass()(只能是相同的对象),instanceof(可以是对象的子类)

如果重写equals()hashcode()也需要重写。因为逻辑上相等的两个对象必须有相同的hash值。

Object.clone()

作用是获得一个独立的,与原对象成员一致的新对象。但是在默认的情况下,只能在子类内克隆自己,所以一般需要在类中重写该方法。其次,一个类想实现克隆,需要实现一个标记接口(不含任何抽象方法的接口)java.lang.Cloneable

浅克隆:如果克隆的类中有引用类型变量,在克隆后该变量会与克隆前的类中的变量指向同一个对象,这样并不能说明这两个类是独立的,这叫做浅克隆。

深度克隆:在clone()中做出如下操作:

  1. 将引用指向的对象,也克隆一份。
  2. 然后让克隆后的引用指向它。

可以让克隆后的引用类型变量指向一个同样被克隆的新的对象,这样就实现了深度克隆。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Student{
Dog d;

//重写clone方法的访问权限
@Override
protected Student clone() throws CloneNotSupportedException {
//仍然选择调用父类默认实现
//深度克隆的步骤
//1.深度克隆是在浅克隆基础上完成的
Student cloneStu = (Student) super.clone();
//2.需要把Dog对象克隆一份
Dog cloneDog = cloneStu.d.clone();
//3.将拷贝引用指向拷贝对象
cloneStu.d = cloneDog;
return cloneStu;
//return ((Student) super.clone());
}
}
本文作者:Ykuri98
本文链接:https://ykuri98.github.io/2022/04/06/%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93%EF%BC%882022-03-31-2022-04-06%EF%BC%89/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可
×