46

重複の可能性:
Java キャスト演算子はどのように機能しますか?
Java キャストの実装

Java でオブジェクト キャスティングがどのように機能するのか、常に疑問に思っています。プリミティブ型の場合、バイナリ表現レベルのほうが似ていることは理解していますが、オブジェクトはどうですか? 実行時にすべてが決定されるようなものですPolymorphismdynamic binding?例えば:

class Parent{
     void A(){}
}
class Child extends Parent{
     @Override
     void A(){}
}

Parent p = new Parent();
Child c = (Child) p;

これは舞台裏でどのように機能しますか? の新しいインスタンスを作成しますChildか? また、キャストしようとするとどうなりますか:

Child b = (Child) new Object();

最後に、プリミティブをラッパー クラスにキャストする場合:

Double d = (Double) 3.3;

キャストする必要がないことはわかっていますが、キャストした場合はどうなりますか? バックエンドで重要なことはありますか?

4

5 に答える 5

19

明示的なキャストを使用する場合、システムに新しいオブジェクトは作成されません ( is のようなオブジェクトではないため、プリミティブ型をobject wrapperにキャストする最後のケースを除きます)。Java のオートボクシング機能により、この明示的なキャストは必要ないことに注意してください。doubleDouble

あなたの(Child) new Object()シナリオでは、 anは a ではないため、 ClassCastExceptionを受け取ります(ただし、逆は真です)。ObjectChild

最初のシナリオに対する答えは、最も複雑です。基本的に、親クラスはインターフェースのように扱われます。を にキャストするChildと、 APIParentのみが使用可能になります。Parentただし、オーバーライドされたメソッドは引き続き呼び出されます。したがって、次のようにします。

Parent p = (Parent) new Child();
p.a();

...クラスのレンズを通して見られているにもかかわらず、Childのは呼び出されます。ただし、 にない 2 番目のメソッドがある場合(たとえば、としましょう)、オブジェクトを にキャストし直さないと、それを呼び出すことはできませんpublic void a()ParentChildParentpublic void b()Child

「舞台裏」とは、あなたが言うように、作成される唯一の新しいものは、同じオブジェクトを指す別のオブジェクト参照です。同じ単一のオブジェクトへの参照はいくつでも持つことができます。次の例を検討してください。

Parent p = new Parent();
Parent p1 = p;
Parent p2 = p;
Parent p3 = p2;

ここでは、4 つの参照 ( pp1p2、および) があり、それぞれが宣言p3で作成した同じオブジェクトを指しています。new Parent()

ただし、哲学的な点については、この新しい参照の作成は、舞台裏ではなく、実際には明示的であると主張するでしょうParent p = something.

リンク:

于 2012-11-15T20:16:23.000 に答える
12

主な質問に対する簡単な答えは「いいえ」です。すべてのキャストは構文チェック時に行われます。

キャストは、構文チェッカーがオブジェクトをどのように見るかに影響します。オブジェクト自体には影響しません。親としてキャストされた子は、引き続き子です。

ただし、キャストは実行時にのみチェックされます。それが危険であり、他に方法がない限り使用すべきではない理由です。

于 2012-11-15T21:38:04.730 に答える
5

これによると、 checkcast、それが行うことは、参照が割り当て可能かどうかを確認することです。そうである場合、スタックは変更されず、その参照に対する操作は保持されます。

あなたが持っている場合:

 Child c = ( Child )  anyObject; 
 c.sayHi();

キャストが成功した場合、メソッドsayHi を呼び出すことができます。

objectref を解決されたクラス、配列、またはインターフェイスの型にキャストできる場合、オペランド スタックは変更されません。それ以外の場合、checkcast 命令は ClassCastException をスローします。

これが「バイトコード」です

$ cat CastDemo.java 
class Parent {}
class Child extends Parent {}
class Main {
    Child c = (Child) new Parent();
}
$ javap -c Main
Compiled from "CastDemo.java"
class Main {
  Child c;

  Main();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0       
       5: new           #2                  // class Parent
       8: dup           
       9: invokespecial #3                  // Method Parent."<init>":()V
      12: checkcast     #4                  // class Child
      15: putfield      #5                  // Field c:LChild;
      18: return        
}
于 2012-11-15T20:22:46.273 に答える
4

まず、変換キャストを混同しないように注意してください。これらは表面的な構文を共有している場合がありますが、プロセスは大きく異なります。

Java では、オブジェクトを任意の型にダウンキャストできますが、実行時にClassCastException、オブジェクトが実際にターゲットの型と互換性がない場合は を取得します。これはバイトコード レベルで発生します。ダウンキャスト専用のバイトコード命令があります。

Child c = (Child) new Object();

無条件に になりClassCastExceptionます。

Double d = 3.3; // note: no explicit casting needed

のインスタンスへのオートボクシングを実行しますDouble。ここで、実際に新しいインスタンスが作成されます。

通常の成功したダウキャストは次のようになります。

Object o = "a";
String s = (String)o;

ここでは、オブジェクトは作成されません。 の値のみoが にコピーされsます。数値は参考値です。

于 2012-11-15T20:15:30.037 に答える
3

オブジェクトのダウンキャストは、そのオブジェクトに対して何もしていません。舞台裏で、コンパイラはcheckcastバイトコード操作を挿入します。pが実際には のインスタンスでない場合Child、例外がスローされます。それ以外の場合は、基本的に、より具体的なタイプが異なる同じオブジェクトへの (タイプ) セーフな参照があります。


Child b = (Child) new Object();

これは で失敗しClassCastExceptionます。JVMgetClass()は と を比較new Object()Child.classます。Object.classは のサブクラスではないため、Child.class例外がスローされます。


Double d = (Double) 3.3;

ここでは、キャストは必要ありません。これも同様に機能します: Double d = 3.3. 舞台裏では、これは次のように翻訳されています。

Double d = Double.valueOf(3.3);

これは、オートボクシングとして知られています。

于 2012-11-15T20:17:26.263 に答える