1

これはKathy Sierra による"SCJP"の例です: Chapter 2 - Object Orientation

class X { void do1() {} }

class Y extends X { void do2() {} }

class Chrome {

     public static void main (String args[]) {
         X x1 = new X();
         X x2 = new Y(); //***** question is regarding this line
         Y y1 = new Y();
         ((Y)x2).do2();
     }
}

2 つのコンストラクターを使用してオブジェクトを作成することは合法ですか? x2また、 :Xまたは?とはどのような種類のオブジェクトYですか?

4

6 に答える 6

3

これらは2つのコンストラクターではありません

 X x2 = new Y(); 
  • X変数の型
  • x2は を参照できる参照変数でありX、したがって の任意のサブクラスですX。この場合、 を参照できますY
  • new Y()実際にYメモリ内にクラスのオブジェクトを作成し、変数xはオブジェクトを参照します。

これはY拡張されてXいるため可能であり、IS-Aテストに合格します。これはポリモーフィズムの例です。スーパー タイプがサブタイプのオブジェクトを参照しています。

  • コンパイル時に、x2参照変数は型になりますX
  • 実行時に、x2タイプ のサブクラス オブジェクトを参照しますY

したがって、 classXのメソッドによってオーバーライドされる classのメソッドがある場合、オブジェクトの型が であるため、Yclass のメソッドが呼び出されます。YY

これらのクラスを検討してください。

public class X {

    public void someMethod(){
        System.out.println("we are in class X method");
    }
}

そして別のクラス

public class Y extends X {

    public void someMethod(){
        System.out.println("we are in class Y method ");
    }


    public static void main(String [] args){
        X x = new X();
        X x2 = new Y();
        Y y = new Y();

        x.someMethod();
        x2.someMethod();
        y.someMethod();
    }

}

これは出力します

we are in class X method
we are in class Y method 
we are in class Y method 

説明は次のとおりです。

  • このステートメントは、 classのso 呼び出しを参照してX x = new X();object を作成します。XXsomeMethodX
  • このステートメントはクラスのオブジェクト以外のX x2 = new Y();参照変数を作成するため、オーバーライドされたメソッドには動的バインディングがあるため、クラスのオーバーライド メソッドが呼び出されます。どのオーバーライドされたメソッドを呼び出すかは、オブジェクトの種類によって異なります。XYY
  • についてはY y = new Y()、ポイント1と同じ説明。
于 2013-08-02T13:15:03.203 に答える
1

x2コンパイル時の型は ですXが、実行時の型はYです。これが意味することは、コンパイラがx2それについて推論する必要があるとき、それx2X. しかし、実行時には、 の動作は の動作にx2なりますY

では、これをもう少し冗長に説明しましょう。これは合法ではありません:

x2.do2();

これは、コンパイラがそれをx2であるXと見なしX、 という名前のメソッドを持たずdo2、 しかY持たないためです。コンパイラは が であることを認識せず、 のコンパイル時の型が であるx2ことYのみを認識します。x2X

ただし、これは正当であり、実行時例外は発生しません。

((Y)x2).do2();

私たちはコンパイラに、ほら、私はあなたよりも について知っていると言っていますx2。であることはわかっているので、 を受信側としてY呼び出す命令を発行するだけY.do2です。x2

さらに、 s を受け入れるメソッドがあると仮定しましょうY:

void M(Y y) { }

次に、これは合法ではありません。

M(x2);

繰り返しますが、これは、すべての s がs でx2あるとは限らず、コンパイラーがそれを と見なすためです。そのため、メソッドの呼び出しを拒否する必要があります。XXY

ただし、これは正当であり、実行時例外は発生しません。

M((Y)x2);

繰り返しますが、私たちはコンパイラに、あなたが知っているよりも多くのことを知っていると伝えていますx2。私はそれが であることを知っているYので、私を信じて、あたかもx2であるかのようにそのメソッドを呼び出してくださいY

Xさらに、 で定義され、 でオーバーライドされたメソッドがあると仮定しましょうY:

class X {
    void do1() {}
    void N() { System.out.println("X");
}

class Y extends X { void do2() {} 
    @Override
    void N() { System.out.println("Y");
}

ここで、次のように言います。

x2.N();

Yコンソールに表示されます。これは、 のランタイムタイプが であるためx2ですY

これらはすべて、人々がポリモーフィズムについて話すときの意味の一部です。

2 つのコンストラクターを使用してオブジェクトを作成することは合法ですか?

このステートメントには 2 つのコンストラクターはありません。

X x2 = new Y();

コンストラクターは 1 つだけです。左辺は変数宣言です。x2typeという名前の変数を宣言していますX。右側はコンストラクターの呼び出しです。Y;のパラメーターなしのパブリック コンストラクターを呼び出しています。これにより、 の新しいインスタンスが作成されますY。ステートメント全体が代入ステートメントです。右側の結果を左側の変数に代入しています。Yすべての s はポリモーフィックにもXs であるため、代入は正当ですY extends X

于 2013-08-02T13:15:19.623 に答える
0

はい、それは合法であり、2 つのコンストラクターではなく、参照型が異なるだけです。

インスタンスはY型ですが、参照はX型です。したがって、その上でメソッドを呼び出すことはできませんY

new Y()Y aka Runtime型の新しいインスタンスを作成します

X x2 = new Y();X は Y のスーパークラスであるため、Y を保持できる型 X (別名コンパイル時型)の参照に割り当てます。

テストする:

if(x2 instanceof Y){
   System.out.println("Instance is of Y");
}
于 2013-08-02T13:15:03.583 に答える
0

x2実際にはY実行時のオブジェクトです。コンパイル時にx2は、オブジェクトのように扱われXます。

これは、コンパイル時に、どのタイプのオブジェクトを扱うかを実際には知らないかもしれませんが、 から継承するオブジェクトを扱うことはわかっているポリモーフィズムに非常に役立ちますX

于 2013-08-02T13:15:42.723 に答える
0

派生クラスは、クラス階層の型の変数にいつでも割り当てることができます。

X x = new Y();  // is valid.
Y y = x;   // is not valid without a cast, even though x is actually of class Y

したがって、Y のオブジェクトを X 型の変数に割り当てることは有効ですが、その逆は有効ではありません。

X で関数を呼び出し、それらが Y でオーバーライドされると、それらも呼び出されます。ただし、Y が新しい関数を導入した場合、もちろん X からそれらを呼び出すことはできません。

于 2013-08-02T13:17:17.620 に答える
0

別のコンストラクターを使用するコンストラクターを使用してオブジェクトを作成することは合法です。

于 2013-08-02T13:19:51.930 に答える