Java Object Cast如何在场景后工作?

时间:2012-11-15 20:11:29

标签: java casting polymorphism

  

可能重复:
  How does the Java cast operator work?
  Java casting implementation

我总是想知道如何在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;

我知道你没有必要施展它,但如果你这样做呢?在后端发生了什么重大事件?

5 个答案:

答案 0 :(得分:15)

使用显式强制转换时,系统中不会创建新对象(在上一种情况下,将基本类型转换为object wrapper除外,因为double不是Double之类的对象1}}是。请注意,由于Java autoboxing feature

,因此不需要此显式强制转换

(Child) new Object()方案中,您会收到ClassCastException,因为Object不是Child(尽管情况相反)。

你的第一个场景的答案是最复杂的。基本上,父类被视为接口可能是。将Child投射到Parent时,只有Parent API可用。但是,the overridden method will still be called。所以,如果你这样做:

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

... Child的{​​{1}}将被调用,即使它是通过public void a()类镜头看到的。但是,如果您在Parent中使用Child的第二种方法(例如Parent),那么 调用它而不将对象强制转换回public void b()

“幕后花絮”,正如你所说,创造的唯一新事物是指向同一个物体的另一个object reference。您可以根据需要为同一个单一对象提供尽可能多的引用。考虑这个例子:

Child

此处有四个引用(Parent p = new Parent(); Parent p1 = p; Parent p2 = p; Parent p3 = p2; pp1p2),每个引用都指向您使用{{1}创建的同一对象声明。

但是,我可能会在哲学观点上争论,当你说p3时,这种新引用的创建实际上是明确的而不是幕后的。

<强>链接:

答案 1 :(得分:9)

您的主要问题的简单答案是否定的。 所有转换都发生在语法检查时。

强制转换会影响语法检查器查看对象的方式, 它不会影响对象本身的一个Child转换为a 父母,还是个孩子。

然而,仅在运行时检查演员表。 这就是为什么它是危险的,不应该使用 除非没有别的办法。

答案 2 :(得分: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        
}

答案 3 :(得分:2)

首先,要非常小心,不要将转化投射混淆。它们可能共享表面语法,但是过程非常不同。

在Java中,您可以将Object转发为任何类型,但在运行时,如果对象实际上与目标类型不兼容,则会获得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。该值是参考。

答案 4 :(得分:1)

向下转换对象并没有对该对象做任何事情。在幕后,编译器将注入checkcast字节码操作。如果p实际上不是Child的实例,则会抛出异常。否则,您基本上对具有不同,更具体类型的同一对象具有(类型)安全引用。


Child b = (Child) new Object();

ClassCastException失败。 JVM将getClass() new Object()Child.class进行比较。由于Object.class不是Child.class的子类,因此抛出异常。


Double d = (Double) 3.3;

在这里,甚至不需要施法,这也有效:Double d = 3.3。在幕后,这被翻译成:

Double d = Double.valueOf(3.3);

这称为Autoboxing