最近在肝Java的基础教程,多态真是个令新人头疼的东西…

好不容易理解了多态的方法特点,结果又整出来俩例外?!没错,就是成员和静态…

多态の特点

成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Demo01 {
public static void main(String[] args) {
SuperClass superc = new SubClass();
System.out.println(superc.num);
}
}

class SuperClass{
int num = 3;
}

class SubClass extends SuperClass{
int num = 1;
}

以上代码的执行结果是多少呢?

按照通常多态的逻辑,建立的子类对象应当覆盖父类才对。但多态中的成员变量有这样的特性:成员变量参考引用型变量所属的类。

方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Demo01 {
public static void main(String[] args) {
SuperClass superc = new SubClass();
superc.print();
}
}

class SuperClass{
static void print(){
System.out.println("The method of superClass.");
}
}

class SubClass extends SuperClass{
static void print(){
System.out.println("The method of subClass.");
}
}

以上代码同样,在静态中,不会调用实际指向对象的静态方法,而是调用引用型变量所指类的静态方法。

个人的理解

这个现象加上之前所学的多态的基本特点确实有点让人头大,咱是这样子理解的:

new SubClass() 时,SubClass 和 SuperClass 的 num 都被加载进内存,当使用父类的引用访问 num 时,优先访问父类的成员。(讲了个寂寞)

new SubClass() 时,由于子类继承父类,所以子类和父类都被加载进内存,但由于 print 方法是静态的,在类加载的时候,就被加载进内存并与对应的类绑定在一起。所以 在调用 superc.print() 时,实际上是从类名调用的该静态方法 SuperClass.print() 。也就是说多态时访问静态方法只参考引用变量的类,而不考虑引用变量所指的实际对象。


但是以上的情况在实际开发中并不多见,在面试中更常见一些。

小小な想法

学习了上面多态的特性,那么肯定是要找一个栗子来巩固一下啦。

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
public class Demo01 {
public static void main(String[] args) {
SuperClass superc = new SubClass();
superc.print();
System.out.println(superc.num + "\t" + superc.a);
}
}

class SuperClass {
static int num = 3;
int a = 4;

void print() {
System.out.println(num + "\t" + a);
}
}

class SubClass extends SuperClass {
static int num = 1;
int a = 2;

void print() {
System.out.println(num + "\t" + a);
}
}

以上代码的输出应该是什么呢~如果没理解刚刚学的的多态的特点的话估计已经头晕了叭233

1 2

3 4

输出就是酱,下面来仔细分析一下为什么是这样的输出结果叭!

首先是 new 了一个 SubClass 并给 superc ,那么现在就有一个 superc 的引用,引用的类型是 SuperClass 但是它的指向是一个 SubClass 的对象。

现在调用了 superc 引用的 print 方法,由于该方法不是静态的,所以实际上调用的是该引用指向对象的 print 方法——被 SubClass 复写过的 print 方法。

在 SubClass 类的 print 方法中,打印了一个 num 和一个 a ,由于 superc 是对 SubClass 的引用,所以打印的 a 是本类中的成员,也就是 2 ,而这个 num 由于是在本类中对本类成员进行访问,所以结果是 1。

下一行直接调用 superc.num 和 superc.a 的时候,由于这个属于多态情况,所以都只参考引用变量的类。