Java编程思想学习笔记(二)—— 多态

一般情况

在 Java 中使用多态需要注意以下几点:

  1. 如果某个方法是静态的, 那么该方法就不具有多态性
  2. final 修饰的方式是不可被覆盖
  3. private 修饰的方法不具备多态性,会被系统自动认为是 final 修饰的方法,同时对于子类是屏蔽的
  4. 虽然子类中可以拥有父类中 private 修饰的同名方法,编译器不会报错,但是并不会按照我们所期望的运行,所以做好不要采用相同的名字

以代码为例

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
30
31
32
33
34
35
36
public class MultiTypeTest {
public static void f3() {
System.out.println("multi static");
}
private void f1() {
System.out.println("multi f1()");
}
public void f2() {
System.out.println("multi f2()");
}
public static void main(String[] args) {
MultiTypeTest test = new NewType();
test.f1();
test.f2();
test.f3();
}
}
class NewType extends MultiTypeTest {
public void f1() {
System.out.println("new f1()");
}
public void f2() {
System.out.println("new f2()");
}
public static void f3() {
System.out.println("new static");
}
}

运行结果如下:

1
2
3
multi f1()
new f2()
multi static

由运行结果可知,f1() 方法的对比对应的是第3点和第4点,f3() 方法的对比对应的是第1点,至于第二点,编译器会报错。

总结

  1. 子类继承父类,子类可以继承父类的所有非 private 方法和属性,同时也可以重写父类非 final 和 static 修饰的方法
  2. 当子类的引用指向父类的对象时,父类的对象除可以调用自己本身的属性和方法外,只能调用子类重写的方法,不可调用子类特有的方法和属性。

构造器内部的多态

构造器初始化的实际过程:

  1. 在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制的零。
  2. 调用基类构造方法。此时如果基类构造方法中调用了一个方法,该方法在子类中被重写过,那么实际调用的是子类重写的方法,见稍后代码。
  3. 按照申明顺序调用成员的初始化方法
  4. 调用子类的构造方法

示例代码:

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
class Base {
void print() {
System.out.println("print()");
}
public Base() {
System.out.println("base() before");
print();
System.out.println("base() after");
}
}
class ExtendBase extends Base {
private int value = 1;
void print() {
System.out.println("extend, value = "+ value);
}
public ExtendBase(int value) {
System.out.println("extend init before, value = "+ this.value);
this.value = value;
System.out.println("extend init after, value = "+ this.value);
}
}
public class MultiTypeTest {
public static void main(String[] args) {
new ExtendBase(5);
}
}

输出结果:

1
2
3
4
5
base() before
extend, value = 0
base() after
extend init before, value = 1
extend init after, value = 5

有结果可知,先初始基类构造方法,之后由于基类构造方法里调用了 print() 方法,故调用的是子类的 print() 方法,同时此时的 value 值为0(参见第一点), 之后便是正常的顺序执行初始化过程。