web-dev-qa-db-ja.com

Javaでのダウンキャスト

Javaではアップキャストが許可されていますが、ダウンキャストではコンパイルエラーが発生します。

コンパイルエラーはキャストを追加することで削除できますが、実行時にとにかく壊れます。

この場合、実行時に実行できない場合にJavaがダウンキャストを許可するのはなぜですか?
この概念の実用的な用途はありますか?

public class demo {
  public static void main(String a[]) {
      B b = (B) new A(); // compiles with the cast, 
                         // but runtime exception - Java.lang.ClassCastException
  }
}

class A {
  public void draw() {
    System.out.println("1");
  }

  public void draw1() {
    System.out.println("2");
  }
}

class B extends A {
  public void draw() {
    System.out.println("3");
  }
  public void draw2() {
    System.out.println("4");
  }
}
168
Warrior

ダウンキャスティングは、実行時に成功する可能性がある場合に許可されます。

Object o = getSomeObject(),
String s = (String) o; // this is allowed because o could reference a String

場合によっては、これは成功しません。

Object o = new Object();
String s = (String) o; // this will fail at runtime, because o doesn't reference a String

他では動作します:

Object o = "a String";
String s = (String) o; // this will work, since o references a String

実行時にキャスト(この最後のキャストなど)が失敗すると、 ClassCastException がスローされます。

一部のキャストは、決して成功しないため、コンパイル時に許可されないことに注意してください。

Integer i = getSomeInteger();
String s = (String) i; // the compiler will not allow this, since i can never reference a String.
282
Joachim Sauer

あなたの例を使用すると、次のことができます:

public void doit(A a) {
    if(a instanceof B) {
        // needs to cast to B to access draw2 which isn't present in A
        // note that this is probably not a good OO-design, but that would
        // be out-of-scope for this discussion :)
        ((B)a).draw2();
    }
    a.draw();
}
16
Rolf Rander

これは静的に型付けされたすべての言語に当てはまると思います。

String s = "some string";
Object o = s; // ok
String x = o; // gives compile-time error, o is not neccessarily a string
String x = (String)o; // ok compile-time, but might give a runtime exception if o is not infact a String

タイプキャストは効果的に、これがキャストクラスへの参照であると想定し、そのように使用します。ここで、oが本当に Integerであるとしましょう。これが理にかなっていて予期しない結果をもたらすと仮定すると、ランタイムチェックと例外がランタイム環境に通知される必要があります。違う。

実際の使用では、より一般的なクラスで動作するコードを記述できますが、サブクラスが何かを知っていて、そのように扱う必要がある場合は、サブクラスにキャストします。典型的な例は、Object.equals()のオーバーライドです。 Carのクラスがあると仮定します。

@Override
boolean equals(Object o) {
    if(!(o instanceof Car)) return false;
    Car other = (Car)o;
    // compare this to other and return
}
15
Rolf Rander

提供されたコードは実行時に機能しないことがすべてわかります。これは、式new A()neverB型のオブジェクトになる可能性があることを知っているためです。

しかし、それはコンパイラがそれを見る方法ではありません。コンパイラがキャストが許可されているかどうかを確認するまでに、次のように表示されます。

variable_of_type_B = (B)expression_of_type_A;

そして、他の人が示したように、そのようなキャストは完全に合法です。右側の式は、B型のオブジェクトに非常によく評価できます。コンパイラーは、ABにサブタイプの関係があることを認識しているため、コードの「式」ビューではキャストが機能する可能性があります。

コンパイラは、正確にexpression_of_type_Aが実際に持っているオブジェクト型を知っている場合、特別な場合を考慮しません。静的型をAとして認識し、動的型はAまたはAを含むBの子孫であると見なします。

5
Rob Kennedy

この場合、実行時に実行できない場合にJavaがダウンキャストを許可するのはなぜですか?

これは、キャストが成功するかどうかをコンパイラがコンパイル時に知る方法がないためだと思います。たとえば、キャストが失敗するのは簡単ですが、それほど明確ではない場合もあります。

たとえば、タイプB、C、およびDがすべてタイプAを拡張し、public A getSomeA()メソッドが、ランダムに生成された数値に応じてB、C、またはDのインスタンスを返すとします。コンパイラーは、このメソッドによってどの正確なランタイム型が返されるかを知ることができないため、後で結果をBにキャストした場合、キャストが成功(または失敗)するかどうかを知る方法はありません。したがって、コンパイラはキャストが成功すると想定する必要があります。

3
matt b

@オリジナルポスター-インラインコメントを参照してください。

public class demo 
{
    public static void main(String a[]) 
    {
        B b = (B) new A(); // compiles with the cast, but runtime exception - Java.lang.ClassCastException 
        //- A subclass variable cannot hold a reference to a superclass  variable. so, the above statement will not work.

        //For downcast, what you need is a superclass ref containing a subclass object.
        A superClassRef = new B();//just for the sake of illustration
        B subClassRef = (B)superClassRef; // Valid downcast. 
    }
}

class A 
{
    public void draw() 
    {
        System.out.println("1");
    }

    public void draw1() 
    {
        System.out.println("2");
    }
}

class B extends A 
{
    public void draw() 
    {
        System.out.println("3");
    }

    public void draw2() 
    {
        System.out.println("4");
    }
}
2
Alok Sharma

ダウンキャストは、アップキャストされたオブジェクトを処理する場合に機能します。アップキャスティング:

int intValue = 10;
Object objValue = (Object) intvalue;

したがって、キャストされたオブジェクトはobjValueであるため、このint変数は常にIntegerにダウンキャストできます。

int oldIntValue = (Integer) objValue;
// can be done 

ただし、objValueはObjectであるため、Stringintにキャストできないため、Stringにキャストできません。

1
Uday Reddy

オブジェクトのダウンキャスト変換はできません。 「DownCasting1 _downCasting1 =(DownCasting1)((DownCasting2)downCasting1);」のみ可能です

class DownCasting0 {
    public int qwe() {
        System.out.println("DownCasting0");
        return -0;
    }
}

class DownCasting1 extends DownCasting0 {
    public int qwe1() {
        System.out.println("DownCasting1");
        return -1;
    }
}

class DownCasting2 extends DownCasting1 {
    public int qwe2() {
        System.out.println("DownCasting2");
        return -2;
    }
}

public class DownCasting {

    public static void main(String[] args) {

        try {
            DownCasting0 downCasting0 = new DownCasting0();
            DownCasting1 downCasting1 = new DownCasting1();
            DownCasting2 downCasting2 = new DownCasting2();

            DownCasting0 a1 = (DownCasting0) downCasting2;
            a1.qwe(); //good

            System.out.println(downCasting0 instanceof  DownCasting2);  //false
            System.out.println(downCasting1 instanceof  DownCasting2);  //false
            System.out.println(downCasting0 instanceof  DownCasting1);  //false

            DownCasting2 _downCasting1= (DownCasting2)downCasting1;     //good
            DownCasting1 __downCasting1 = (DownCasting1)_downCasting1;  //good
            DownCasting2 a3 = (DownCasting2) downCasting0; // Java.lang.ClassCastException

            if(downCasting0 instanceof  DownCasting2){ //false
                DownCasting2 a2 = (DownCasting2) downCasting0;
                a2.qwe(); //error
            }

            byte b1 = 127;
            short b2 =32_767;
            int b3 = 2_147_483_647;
//          long _b4 = 9_223_372_036_854_775_807; //int large number max 2_147_483_647
            long b4 = 9_223_372_036_854_775_807L;
//          float _b5 = 3.4e+038; //double default
            float b5 = 3.4e+038F; //Sufficient for storing 6 to 7 decimal digits
            double b6 = 1.7e+038;
            double b7 = 1.7e+038D; //Sufficient for storing 15 decimal digits

            long c1 = b3;
            int c2 = (int)b4;

            //int       4 bytes     Stores whole numbers from -2_147_483_648 to 2_147_483_647
            //float     4 bytes     Stores fractional numbers from 3.4e−038 to 3.4e+038. Sufficient for storing 6 to 7 decimal digits
            float c3 = b3; //logic error
            double c4 = b4; //logic error


        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

}
0

ダウンキャストは、私がこれを常に使用する次のコードスニペットで非常に役立ちます。したがって、ダウンキャストが有用であることを証明します。

private static String printAll(LinkedList c)
{
    Object arr[]=c.toArray();
    String list_string="";
    for(int i=0;i<c.size();i++)
    {
        String mn=(String)arr[i];
        list_string+=(mn);
    }
    return list_string;
}

リンクリストに文字列を格納します。リンクリストの要素を取得すると、オブジェクトが返されます。要素を文字列(または他のクラスオブジェクト)としてアクセスするには、ダウンキャストが役立ちます。

Javaを使用すると、間違ったことをしていると信じてダウンキャストコードをコンパイルできます。それでも人間が間違いを犯した場合、実行時にキャッチされます。

0
Drishti

以下の例を考えてください

public class ClastingDemo {

/**
 * @param args
 */
public static void main(String[] args) {
    AOne obj = new Bone();
    ((Bone) obj).method2();
}
}

class AOne {
public void method1() {
    System.out.println("this is superclass");
}
}


 class Bone extends AOne {

public void method2() {
    System.out.println("this is subclass");
}
}

ここで、サブクラスBoneのオブジェクトを作成し、それをスーパークラスAOne参照に割り当てましたが、スーパークラス参照は、サブクラスのメソッドmethod2、つまりコンパイル時にBoneを認識しません。したがって、スーパークラスのこの参照をサブクラス参照にダウンキャストする必要があります。結果の参照は、サブクラス(Bone)のメソッドの存在について知ることができます

0
ZohebSiddiqui