<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Read Sean

    Read me, read Sean.
    posts - 508, comments - 655, trackbacks - 9, articles - 4

    你真的理解了繼承和多態嗎?

    Posted on 2005-06-07 15:18 laogao 閱讀(7671) 評論(14)  編輯  收藏 所屬分類: On JavaProgramming in General

    最近被同事問起一道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,時不時抽空想想這樣的問題感覺真不錯。

    Feedback

    # re: 你真的理解了繼承和多態嗎?  回復  更多評論   

    2005-06-07 16:26 by 小毅
    謝謝您,學到很容易忽略的東西,覺得很重要
    再謝謝你...

    # 原來字段和方法有這樣的區別哦  回復  更多評論   

    2005-06-08 09:02 by emu
    >>只有方法的多態而沒有字段的多態

    以前都沒有想過這個問題哦。

    前兩天遇到一個內嵌類的方法重載時候的古怪問題,不知是否與此有關,正好回頭去研究一下。

    # re: 你真的理解了繼承和多態嗎?  回復  更多評論   

    2005-06-08 12:16 by FS
    Java的對象模型偶不太清楚,不過通過對Delphi的對象模型的了解,我感覺應該和Java沒有太大的區別。

    按照樓主所說的,當執行了語句“a=b”后,變量a和b的內容應該是不變的,所變的是a指向的對象實體中的指向類的指針的內容,在Delphi中,這個指針叫做vptr,CPP中也是如此叫法。vptr直接指到類的VMT(不知道Java中如何叫法);因此,再次使用a.s訪問實例變量,則要進入b指向的對象實體中進行字段的查找,但由于b里面存在兩個s字段,并且以類型信息為區分方式,所以找到的是類型A的字段s。至于編譯處理方面,我想應該是把類型信息作為字段的前綴或者后綴。

    同樣,當執行了“((A)b).s=“[AA]””后,由于已經把b的類型轉化為A類型,而且b指針的未改變,所以在b的對象實體中,實際改變的是屬于類型A的字段s的內容。個人感覺,其實樓主已經說出了,對b中不同類型的同名字段的訪問方式。

    最后留下一個問題:這種對象模型中的字段處理方式如果在繼承字段訪問量小的情況下是很浪費空間的。那么,這樣處理的優點又是什么?

    # re: 你真的理解了繼承和多態嗎?  回復  更多評論   

    2005-06-08 12:18 by FS
    按照OO這種東西在語言設計上的考慮,對象所涉及到的所有內容就是三塊:對象指針,對象實體和對象所屬類型的內存布局。而對象實體中只存放狀態信息,即對象所屬類型的實例字段的內容,因此,從這個角度考慮,多態和實例字段的信息是沒有任何關系的。但對于類字段,即申明為static的字段就未必了。

    # re: 你真的理解了繼承和多態嗎?  回復  更多評論   

    2005-07-20 23:24 by 丑男
    System.out.println(a.s); // prints "[A]"
    這句確實我沒想到!看來真被難倒了

    # re: 你真的理解了繼承和多態嗎?  回復  更多評論   

    2006-05-15 17:30 by songxu
    非常感謝

    # re: 你真的理解了繼承和多態嗎?  回復  更多評論   

    2006-07-15 17:22 by tcpipok
    我是想到了,不過就像樓主所說的,這種編碼風格不好,子類盡量不要用父類用過的變量名,真的是容易搞混,這種代碼用來考試可以,但用來編程不好.

    # re: 你真的理解了繼承和多態嗎?  回復  更多評論   

    2006-08-17 20:34 by 小小
    請問:
    java中字符串的連接是不是一種多態的表現?

    # re: 你真的理解了繼承和多態嗎?  回復  更多評論   

    2007-03-05 22:52 by 谷鈺
    @tcpipok
    我不知道你是否理解OO真正的精髓,以上用法展示了面向對象設計的核心思想,通過虛方法調用,實現不同子類對同一行為(方法)的不同實現。希望以下例子可以給大家一些啟發:

    # re: 你真的理解了繼承和多態嗎?  回復  更多評論   

    2007-03-05 23:05 by 谷鈺
    public class Employee {

    protected String name = "張三";

    private double salary = 1000;

    public Employee(String name, double salary) {
    this.name = name;
    this.salary = salary;
    }

    public Employee() {
    this("王老五", 1);
    }

    public String getDetails() {
    return "姓名:" + this.name + ", 工資: " + this.salary;
    }

    public double getSalary() {
    return this.salary;
    }

    public void setSalary(double salary) {
    this.salary = salary;
    }

    public String getName() {
    return this.name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public boolean equals(Object o) {
    if (this == o) {
    return true;
    }

    if (o instanceof Employee) {
    Employee te = (Employee) o;

    return this.salary == te.getSalary() && this.name.equals(te.getName());
    }

    return false;
    }

    public int hashCode() {
    if (this.name == null) {
    return 0;
    }
    return this.name.hashCode();
    }

    public String toString() {
    return "$$" + this.getDetails();
    // return super.toString();
    }

    public static void printAll(Employee[] all) {
    System.out.println("所有員工:");
    for (int i = 0; i < all.length; ++i) {
    System.out.println(all[i].getDetails());
    }
    }

    public static void main(String[] args) {
    Employee e = new Employee("張三", 2500);
    System.out.println(e.getDetails());

    Manager m = new Manager("李四", 4500, "軟件開發部");
    System.out.println(m.getDetails());

    Employee ee = new Manager("王五", 4500, "軟件銷售部");
    System.out.println(ee.getDetails());

    if (ee instanceof Manager) {
    Manager mmm = (Manager) ee;
    System.out.println(mmm.getDepartment());
    }

    Employee e2 = new Employee("張三", 2500);
    System.out.println(e.equals(e2));

    System.out.println(e);
    System.out.println("##" + e);

    Employee[] eAll = {
    e, m, ee
    };
    printAll(eAll);
    }
    }

    class Manager extends Employee {
    private String department = "44";

    public Manager() {
    super();
    this.department = "計算機";
    }

    public Manager(String name, double salary, String department) {
    super(name, salary);

    this.department = department;
    }

    public String getDetails() {
    return super.getDetails() + ", 管理部門: " + this.department;
    }

    public String getDepartment() {
    return this.department;
    }
    }

    # re: 你真的理解了繼承和多態嗎?  回復  更多評論   

    2007-03-05 23:11 by 谷鈺
    核心在
    public static void printAll(Employee[] all) {
    System.out.println("所有員工:");
    for (int i = 0; i < all.length; ++i) {
    System.out.println(all[i].getDetails());
    }
    }
    函數的設計上,通過Employee隱藏所有雇員子類的細節,通過getDetails()方法來隱藏不同雇員(Manger,Engineer等)對詳細信息的函數細節。

    只有這樣的函數才能最大程度上復用,既當設計有新的Employee子類定義也不許要對此函數做任何的修改,個人認為面向對象的最大好處是提高程序的復用性,降低維護成本。這些需要多態,繼承才能作到。:)

    # re: 你真的理解了繼承和多態嗎?  回復  更多評論   

    2007-03-06 09:38 by 大胃
    謝謝 谷鈺 的回復!

    # re: 你真的理解了繼承和多態嗎?  回復  更多評論   

    2008-05-21 17:06 by tonytang
    to 谷鈺,你的代碼也沒有回答tcpipok的疑問啊。子類和父類定義相同的屬性有意義嗎?

    # re: 你真的理解了繼承和多態嗎?  回復  更多評論   

    2008-06-25 11:00 by shell
    寫的太好了。
    學習了很多。
    主站蜘蛛池模板: 日韩国产免费一区二区三区| 巨胸喷奶水www永久免费| 久久WWW免费人成一看片| 国产亚洲精品国产| 久久精品国产免费| 91在线精品亚洲一区二区| 成人片黄网站色大片免费观看APP| 4338×亚洲全国最大色成网站| 人与动性xxxxx免费| 国产精品亚洲产品一区二区三区 | 亚洲乱码中文字幕综合234| 瑟瑟网站免费网站入口| 亚洲女人被黑人巨大进入| 日韩在线观看免费完整版视频| 亚洲美女高清一区二区三区| 国产在线精品一区免费香蕉| 亚洲AV电影院在线观看| 在线看片v免费观看视频777| 亚洲精品第一综合99久久| 国产成人在线免费观看| 国产精品永久免费| 亚洲精品高清久久| 最近最新中文字幕完整版免费高清 | 免费萌白酱国产一区二区三区| 亚洲AV无码第一区二区三区| 中文免费观看视频网站| 亚洲国产精华液2020| 久久亚洲av无码精品浪潮| 日本亚洲欧洲免费天堂午夜看片女人员| 97久久精品亚洲中文字幕无码 | 亚洲av日韩av无码av| gogo全球高清大胆亚洲| 久久免费观看国产精品88av| 亚洲不卡视频在线观看| 亚洲麻豆精品国偷自产在线91| 无码国产精品一区二区免费式芒果| 亚洲卡一卡二卡乱码新区| 亚洲国产精品成人网址天堂| 无码国产精品一区二区免费3p| 亚洲日韩精品国产一区二区三区 | 亚洲人成7777影视在线观看|