zoukankan      html  css  js  c++  java
  • 你真的理解了继承和多态吗?


    最近被同事问起一道SCJP的题目,是跟继承和多态有关的。具体的题目我就不重复了,来看一段我自己敲的代码:

     1package sean.work.test;
     2
     3public 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
    28}

    29
    30class A {
    31    String s = "[A]";
    32    String getS() {
    33        return s;
    34    }

    35}

    36
    37class B extends A{
    38    String s = "[B]";
    39    String getS() {
    40        return s;
    41    }

    42}

    43

    这里我们的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重构了,我这里只是为了注释方便。

    // BTW,时不时抽空想想这样的问题感觉真不错。
  • 相关阅读:
    C# 从服务器下载文件
    不能使用联机NuGet 程序包
    NPOI之Excel——合并单元格、设置样式、输入公式
    jquery hover事件中 fadeIn和fadeOut 效果不能及时停止
    UVA 10519 !! Really Strange !!
    UVA 10359 Tiling
    UVA 10940 Throwing cards away II
    UVA 10079 Pizze Cutting
    UVA 763 Fibinary Numbers
    UVA 10229 Modular Fibonacci
  • 原文地址:https://www.cnblogs.com/sean/p/169493.html
Copyright © 2011-2022 走看看