最近被同事问起一道SCJP的题目,是跟继承和多态有关的。具体的题目我就不重复了,来看一段我自己敲的代码:
1
package sean.work.test;
2![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
3
public
class
DoYouReallyUnderstandPolymorphism
{
4
5
public static void main(String[] args) {
6
A a = new A();
7
B b = new B();
8
a.s = "[AA]";
9
b.s = "[BB]";
10
System.out.println(a.s); // prints "[AA]"
11
System.out.println(b.s); // prints "[BB]"
12
System.out.println(a.getS()); // prints "[AA]"
13
System.out.println(b.getS()); // prints "[BB]"
14
System.out.println("====================");
15
a = b; // a now refers to object b
16
System.out.println(a.s); // prints "[A]" <<--1-- the class A copy
17
System.out.println(b.s); // prints "[BB]"
18
System.out.println(a.getS()); // prints "[BB]"
19
System.out.println(b.getS()); // prints "[BB]"
20
System.out.println("====================");
21
((A)b).s = "[AA]"; // <<--2-- changes the class A copy in object b
22
System.out.println(a.s); // prints "[AA]" <<--3-- class A copy changed
23
System.out.println(b.s); // prints "[BB]"
24
System.out.println(a.getS()); // prints "[BB]"
25
System.out.println(b.getS()); // prints "[BB]"
26
}
27![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
28
}
29![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
30
class
A
{
31
String s = "[A]";
32
String getS() {
33
return s;
34
}
35
}
36![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
37
class
B extends A
{
38
String s = "[B]";
39
String getS() {
40
return s;
41
}
42
}
43
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
2
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
3
![](https://i-blog.csdnimg.cn/blog_migrate/1fa987a29c6482f53d401256f96355eb.gif)
4
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
5
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
6
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
7
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
8
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
9
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
10
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
11
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
12
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
13
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
14
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
15
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
16
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
17
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
18
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
19
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
20
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
21
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
22
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
23
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
24
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
25
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
26
![](https://i-blog.csdnimg.cn/blog_migrate/ecedf933ec37d714bd4c2545da43add2.gif)
27
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
28
![](https://i-blog.csdnimg.cn/blog_migrate/8f1ba5b45633e9678d1db480c16cae3f.gif)
29
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
30
![](https://i-blog.csdnimg.cn/blog_migrate/1fa987a29c6482f53d401256f96355eb.gif)
31
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
32
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
33
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
34
![](https://i-blog.csdnimg.cn/blog_migrate/ecedf933ec37d714bd4c2545da43add2.gif)
35
![](https://i-blog.csdnimg.cn/blog_migrate/8f1ba5b45633e9678d1db480c16cae3f.gif)
36
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
37
![](https://i-blog.csdnimg.cn/blog_migrate/1fa987a29c6482f53d401256f96355eb.gif)
38
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
39
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
40
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
41
![](https://i-blog.csdnimg.cn/blog_migrate/ecedf933ec37d714bd4c2545da43add2.gif)
42
![](https://i-blog.csdnimg.cn/blog_migrate/8f1ba5b45633e9678d1db480c16cae3f.gif)
43
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
这里我们的B类继承自A类,重写了getS()方法,于是我们可以利用到多态。如果你留意15、16、21、22这几行的话,你也许就会知道我在说什么了。假如你觉得这样的打印结果是理所当然,那么我想你可以完全忽略这篇随笔,因为我要讲的就集中在这几行,而你已经很清楚的理解背后的含义。
下面跟感兴趣的朋友们说说我的理解:
直观的讲,我们很容易轻信当"a = b;"以后,变量a指向的对象是B类的b那个对象,自然a.s就应该等同于b.s,然而事实并非如此。当B继承A时,父类A的字段s并没有被B的字段s取代,而是保留了一份拷贝,所谓重写(Override),那是对方法而言的。于是,当我们new B()时,在实际创建的对象中,包含了两个版本的字段s,一个"[A]"(属于A类)一个"[B]"(属于B类)。而方法getS()只有一个版本。这就是在继承过程中字段和方法的区别。也就是说,重写的概念和字段无关。在第16行,我们通过a.s访问的是b这个对象中保留的A类的字段s;而在21行,我们改变的正是这个A类版本的s字段。
多态的精髓在于动态确定对象的行为,而对象的行为体现在方法而非字段,字段代表的更多的是对象的状态。于是只有方法的多态而没有字段的多态。从上面的代码可以看出,不管你用什么类型的变量存放对象b的引用,最终调用的方法版本都是b的真实类型那个版本,这就是多态的威力。
从编译的角度来看,上面代码中的s字段和getS()方法的不同在于:s字段是在编译期静态链接(你可以改变它的值,但是它在对象中的相对地址已经确定好),而getS()方法是在运行期动态链接的。
说了这么多,真的不知道我表达清楚没有,毕竟没有系统研究过OO和编译原理,说得不当的地方还请多多包涵。最后,请不要学我这里的编码风格,因为很显然应该对main方法中的代码段执行Extract Method重构了,我这里只是为了注释方便。