可能重复:
How does the Java cast operator work?
Java casting implementation
我总是想知道如何在Java中使用对象转换。我理解原始类型它会更像二进制表示级别,但是对象呢?有点像Polymorphism
或dynamic 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;
我知道你没有必要施展它,但如果你这样做呢?在后端发生了什么重大事件?
答案 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;
,p
,p1
和p2
),每个引用都指向您使用{{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。