在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"); } } 

在运行时有可能发生下行的情况下允许下行:

 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 

请注意,一些演员在编译时将被禁止,因为他们永远不会成功:

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

用你的例子,你可以做到:

 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(); } 

我相信这适用于所有静态types的语言:

 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 

types转换有效地表示:假设这是对类的引用,并将其用于此类。 现在,让我们说o 实际上是一个整数,假设这是一个string没有意义,并会给出意想不到的结果,因此需要有一个运行时检查和一个exception来通知运行时环境有什么错误。

在实际的应用中,你可以编写一个更通用的类的代码,但是如果你知道它是什么子类,就把它转换成一个子类。 一个典型的例子是覆盖Object.equals()。 假设我们有一个汽车类:

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

我们都可以看到你提供的代码在运行时不起作用。 那是因为我们知道new A()expression式永远不可能是typesB的对象。

但是这不是编译器看到的。 当编译器检查是否允许转换时,它只会看到:

 variable_of_type_B = (B)expression_of_type_A; 

正如其他人所表明的那样,这种演员是完全合法的。 右边的expression式可以很好地评估Btypes的对象。 编译器看到AB有一个子types关系,所以在代码的“expression式”视图中,转换可能会起作用。

编译器在确切知道对象typesexpression_of_type_A真正含义时,不会考虑特殊情况。 它只是将静态types看作A并认为dynamictypes可以是AA任何后代,包括B

在这种情况下,为什么Java在运行时无法执行时允许向下转换?

我相信这是因为在编译时编译器没有办法知道转换是否成功。 举个例子,很容易看到演员阵容会失败,但还有一些时候演员阵容不太清楚。

例如,假设typesB,C和D全部扩展typesA,然后public A getSomeA()方法public A getSomeA()根据随机生成的数字返回B,C或D的实例。 编译器无法知道该方法将返回哪个确切的运行时types,所以如果以后将结果转换为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"); } } 

当我们正在处理一个上传的对象时,Downcast就起作用了。 上溯造型:

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

所以现在这个objValuevariables总是可以被转换为int因为被转换的对象是一个Integer

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

但是因为objValue是一个Object,所以不能转换为String因为int不能转换为String

Downcasting在下面的代码片段中非常有用,我总是使用它。 从而certificate向下转换是有用的。

 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; } 

我将string存储在链接列表中。 当我检索链接列表的元素时,返回对象。 要访问元素作为string(或任何其他类对象),向下转换帮助我。

Java允许我们编译相当于我们做错事情的代码。 如果人类犯了一个错误,那么在运行时就会被捕获。

考虑下面的例子

 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"); } } 

这里我们创buildBone子类的对象,并将其分配给超类AOne引用,现在超类引用在编译期间不知道子类Bone中的方法method2。因此,我们需要将这个超类的引用向下转换为子类引用,如所得到的参考可以知道子类即骨中的方法的存在