2013-03-20 40 views
5

下面是我寫的三類:多態性與實例變量

public class Shape { 

    public int x = 0; 

    public void getArea() { 
     System.out.println("I don't know my area!"); 
    } 

    public String toString() { 
     return "I am a shape!"; 
    } 

    public int getX() { 
     return x; 
    } 
} 

public class Rectangle extends Shape { 

    public int x = 1; 

    public int getX() { 
     return x; 
    } 

    public void getArea() { 
     System.out.println("L*W"); 
    } 

    public String toString() { 
     return "I am a rectangle!"; 
    } 
} 

public class Tester { 

    public static void main(String[] args) { 
     Shape s = new Shape(); 
     Rectangle r = new Rectangle(); 

     System.out.println(r); 
     System.out.println(r.x + "\n"); 

     s = r; 
     System.out.println(s); 
     s.getArea(); 
     System.out.println(s.x); 
     System.out.println(s.getX()); 
    } 
} 

從測試類的主要方法的輸出是:

 
I am a rectangle! 

1 

I am a rectangle! 

L*W 

0 

1 

爲什麼s.x返回0而不是1?由於不是變量的當前實例Rectangle,並且該類也具有相同的實例變量聲明,或Rectangle類中的變量是否不覆蓋Shape類中的以前的public x變量,因爲它對getX()方法在矩形類中返回1?

此外,作爲一般規則,超類只有在該類中聲明時纔有權訪問其子類方法的實現?這是否是因爲編譯器會看到具有相同簽名的相同數量的方法在「Shape」類中(使用重寫的Rectangle實現)並將它們接受爲有效的Shape方法?

由於提前,

+0

閱讀更多關於實例變量隱藏爲什麼你的實例變量公開!!?你永遠不應該公開一個實例變量! – DrinkJavaCodeJava 2013-03-20 01:15:11

+0

這是一個測試,看看會發生什麼。我很瞭解封裝,因爲我之前完成了MVC設計。 – PragmaticProgrammer 2013-03-20 03:25:31

回答

13

Java中的字段沒有多態性。然而,有繼承。你有效的做法是在你的Rectangle類中創建兩個具有相同名稱的字段。該字段的名稱,有效:

public class Rectangle { 
    public int Shape.x; 
    public int Rectangle.x; 
} 

以上不代表有效的Java,它只是領域是如何在你的類

範圍的內的整個範圍的說明Rectangle類,同名的超類字段是隱藏。因此,無論何時您在類中引用簡單名稱x或範圍名稱this.x,您都指的是在Rectangle中定義的字段。您實際上也可以訪問超類字段,其範圍名稱爲super.x

現在,從課外以外,訪問字段的規則稍有不同。範圍將由編譯字段被引用的類的時間類型。因此,在你的代碼:

Shape s = new Shape(); 
Rectangle r = new Rectangle(); 

s = r; 
System.out.println(s.x); 

輸出爲0因爲s編譯時類型Shape(不Rectangle)。當你這樣做時,你可以觀察到這種行爲的變化:

Shape s = new Shape(); 
Rectangle r = new Rectangle(); 

s = r; 
System.out.println(((Rectangle)s).x); 

Presto!您的輸出現在爲1,因爲編譯器發現您已將範圍限制爲Rectangle的字段訪問權限。

爲了縮小可視性規則:

您可以在JLS, Section 8.3.3.2

+0

謝謝,我明白了!那麼,當使用s.getArea()時,這些方法使用矩形實現嗎?我知道它們似乎在編譯時實際發生了什麼?謝謝 – PragmaticProgrammer 2013-03-20 03:23:27

+0

@PragmaticProgrammer - 方法的規則是不同的,一方面,它們實際上可以被重寫。請記住我是如何提到的,對於隱藏的變量,解析是在編譯時完成的?那麼對於重寫方法,解決方法是在運行時完成的。所以,如果你做了'Shape s = new Rectangle(); s.getArea();'所調用的方法是用於子類「Rectangle」,而不是用於超類「Shape」。 – Perception 2013-03-20 04:00:28

0

子類繼承唯一變量和方法在超類中,而不是周圍的其他方式。所以爲了讓x等於1,你不得不稱之爲矩形而不是形狀。除非你做了另一個人在演員中演示的東西,你應該儘可能避免在真正的編程中。另外,你永遠不應該使用公共實例變量!如果你想讓變量公開,至少讓它們是靜態的或不變的。