<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
    寫的太好了。
    學習了很多。
    主站蜘蛛池模板: 在线观看片免费人成视频无码| 羞羞视频免费网站含羞草| 久久99毛片免费观看不卡| 久久亚洲色一区二区三区| 国产V片在线播放免费无码| 亚洲精品无码你懂的网站| 四虎影视在线看免费观看| 超清首页国产亚洲丝袜| 91福利免费网站在线观看| 国产精品亚洲а∨无码播放| a级片在线免费看| 亚洲国产精品免费视频| 2019中文字幕免费电影在线播放| 亚洲永久永久永久永久永久精品| 6080午夜一级毛片免费看| 国产亚洲精品VA片在线播放| 在线免费一区二区| 一级黄色片免费观看| 久久久久亚洲精品无码系列| 亚洲免费观看在线视频| 亚洲人成网站免费播放| 国产亚洲午夜高清国产拍精品| 国产精品免费观看调教网| 亚洲大成色www永久网址| 免费一级毛片一级毛片aa| 91成人免费观看在线观看| 久久精品蜜芽亚洲国产AV| 亚洲欧洲免费无码| 暖暖免费中文在线日本| 亚洲AV无码国产精品色午友在线 | 男女一边桶一边摸一边脱视频免费 | 免费a级毛片无码av| 91免费在线视频| 久久精品国产亚洲AV久| 亚洲精品在线视频| 69av免费观看| 国产免费A∨在线播放| 亚洲免费在线视频观看| 亚洲精品成人网久久久久久| 亚洲综合免费视频| 日本特黄特色AAA大片免费|