多型

2013-03-20 17 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()); 
    } 
} 

テスタークラスのmainメソッドからの出力は次のとおりです。

 
I am a rectangle! 

1 

I am a rectangle! 

L*W 

0 

1 

なぜ0ではなく1を返しs.xん?変数の現在のインスタンスではなく、そのクラスにも同じインスタンス変数が宣言されているか、Rectangleクラスの変数は、Shapeクラスの以前のpublic x変数をgetX()メソッドは、矩形クラスの1を返しますか?

また、一般に、スーパークラスはそのクラスで宣言されている場合にのみ、そのサブクラスメソッドの実装にアクセスできますか?これは、同じシグネチャを持つ同じ量のメソッドが "Shape"クラス(オーバーライドされたRectangle実装)にあり、それらを有効なShapeメソッドとして受け入れることをコンパイラが認識するためですか?

+0

にインスタンス変数の隠蔽についての詳細を読むことができます!?インスタンス変数をpublicにしないでください! – DrinkJavaCodeJava

+0

何が起こるかを確認するテストでした。以前はMVCデザインを行っていたので、私はカプセル化について十分に認識しています。 – PragmaticProgrammer

答えて

13

Javaのフィールドの多型はありません。しかし、継承があります。あなたが効果的にやったのは、Rectangleクラスに同じ名前の2つのフィールドを作成することです。事実、あるフィールドの名前:

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

以上が全体の範囲内で有効なJava、フィールドがあなたのクラスにスコープされているか

のそのわずかイラストを表すものではありませんRectangleクラスの場合、同じ名前のスーパークラスフィールドはが隠されていますです。したがって、クラス内の単純名xまたはスコープ付きの名前this.xを参照するときはいつでも、Rectangleで定義されているフィールドを参照しています。スコープ名super.xを使用して、実際にスーパークラスフィールドにアクセスすることもできます。

今、クラスの外から、フィールドがアクセスされているルールは少し異なります。スコープは、によってコンパイルされます。フィールドが参照されているクラスの時刻タイプです。だからあなたのコード内で:sのコンパイル時の型がShape(ないRectangle)であるため、

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

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

出力が0です。これを行うと、この現象の変化を見ることができます。

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

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

Presto!あなたの出力はRectangleにスコープされているとコンパイラに見えるので、出力は1になりました。可視性のルールを凝縮する

あなたはなぜ、あなたのインスタンスが変数公開されてJLS, Section 8.3.3.2

+0

ありがとうございました!では、s.getArea()を使用するときに述べたように、メソッドは長方形の実装を使用しますか?実際にコンパイル時に何が起きているのか分かりますか?ありがとう – PragmaticProgrammer

+0

@PragmaticProgrammer - メソッドのルールは異なりますが、実際にはオーバーライドできます。隠れ変数については、コンパイル時に解決されると述べたことを覚えていますか?オーバーライドされたメソッドの場合、解決は実行時に行われます。したがって、もしあなたが 'Shape s = new Rectangle(); s.getArea(); '呼び出されるメソッドはサブクラス' Rectangle'であり、スーパークラス 'Shape'ではありません。 – Perception

0

サブクラスのみスーパーではなく、周りの他の方法で変数やメソッドを継承し、事前に

おかげで、。したがって、xを1にするには、形状が矩形でないと呼びます。他の人がキャスティングで実演したことを、実際のプログラミングでできるだけ避けなければならない限り行わないといけません。また、これまでに公開されたインスタンス変数を使用しないでください!変数をパブリックにするには、変数を静的または定数にする必要があります。