在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式可以很好地评估B
types的对象。 编译器看到A
和B
有一个子types关系,所以在代码的“expression式”视图中,转换可能会起作用。
编译器在确切知道对象typesexpression_of_type_A
真正含义时,不会考虑特殊情况。 它只是将静态types看作A
并认为dynamictypes可以是A
或A
任何后代,包括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;
所以现在这个objValue
variables总是可以被转换为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。因此,我们需要将这个超类的引用向下转换为子类引用,如所得到的参考可以知道子类即骨中的方法的存在