继承实现的基本原理 (不是很懂的一章)

本节主要从概念上来介绍原理。

首先创建一个基类Base,Base中包含实例变量instanceCode、静态变量staticCode、一段静态初始化代码块、一段实例初始化代码块、一个构造方法、step方法和action方法。

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
27
28
29
public class Base {
public static int staticCode;
private int instanceCode;

static {
System.out.println("基类静态代码块,staticCode: "+staticCode);
staticCode = 1;
}

{
System.out.println("基类实例代码块,actualCode: "+instanceCode);
instanceCode = 1;
}

public Base() {
System.out.println("基类构造方法,actualCode: "+instanceCode);
instanceCode = 2;
}

protected void step() {
System.out.println("base staticCode: "+staticCode+", actualCode: "+instanceCode);
}

public void action() {
System.out.println("start");
step();
System.out.println("end");
}
}

接下来设计出继承Base的子类Child,Child同样包含实例变量actualCode、静态变量staticCode、一段静态初始化代码块、一段实例初始化代码块、一个构造方法,并且重写了step方法。

Child类代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Child extends Base{
public static int staticCode;
private int instanceCode;

static {
System.out.println("子类静态代码块,staticCode: "+staticCode);
staticCode = 10;
}

{
System.out.println("子类实例代码块,instanceCode: "+instanceCode);
}

public Child() {
System.out.println("子类构造方法,instanceCode: "+instanceCode);
instanceCode = 20;
}

@Override
protected void step() {
System.out.println("child staticCode: "+staticCode+", instanceCode: "+instanceCode);
}
}

使用这两个类的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) {
System.out.println("---- new Child()");
Child child = new Child();

System.out.println("\n---- child.action()");
child.action();

Base base = child;
System.out.println("\n---- base.action()");
base.action();

System.out.println("\n---- base.staticCode: "+base.staticCode);
System.out.println("\n---- child.staticCode: "+child.staticCode);
}

child.action()的具体执行过程如下:

1.查看child的对象类型,找到Child类型。在Child类型中寻找action方法,发现没有,于是到Base类中寻找。

2.在Base类中找到了action方法,开始执行该方法。

3.action先输出start,再从Child类型寻找step方法。

4.在Child类型中找到了step方法,执行它,然后返回action方法

5.继续执行action方法, 输出end

寻找要执行的实例方法的时候,是从对象的实际类型信息开始查找的,找不到的时候,再查找父类类型信息。

base.action和child.action都是动态绑定,动态绑定实现的机制,就是根据对象的实际类型查找要执行的方法,子类型中找不到的时候再查找父类。由于base和child指向的动态类型都是Child,所以执行结果一样。

屏幕输入结果为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---- new Child()
基类静态代码块,staticCode: 0
子类静态代码块,staticCode: 0
基类实例代码块,actualCode: 0
基类构造方法,actualCode: 1
子类实例代码块,instanceCode: 0
子类构造方法,instanceCode: 0

---- child.action()
start
child staticCode: 10, instanceCode: 20
end

---- base.action()
start
child staticCode: 10, instanceCode: 20
end

---- base.staticCode: 1

---- child.staticCode: 10

类的加载

在java中,类是动态加载的。

第一次使用这个类的时候才会加载,加载一个类时,会查看其父类是否已加载。如果没有,则加载其父类。

一个类的信息,主要包括以下部分:

  • static变量

  • 类初始化代码

  • static方法

  • 实例变量

  • 实例初始化代码

  • 实例方法

  • 父类信息引用

类初始化代码包括:

  • 定义static变量时的赋值语句

  • static初始化代码块

实例初始化代码包括:

  • 定义实例变量时的赋值语句
  • 实例初始化代码块
  • 构造方法

类加载过程包括:

  • 分配内存,保存类的信息

  • 给static变量赋默认值

  • 加载父类

  • 设置父子关系

  • 执行类初始化代码

类初始化代码,是先执行父类,再执行子类。

父类执行时,子类static变量是有值的,为默认值。

类的信息放在内存区,在java中称为方法区

继承实现.jpg

如上图,class_init()表示类初始化代码,instance_init()表示实例初始化代码。实例初始化代码包括了实例初始化代码块和构造方法。

对于上方的Base类和Child类,它们的内存布局就像图中的方法区。

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2021 Silver Shaded
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信