Java 对象转换在幕后如何工作?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13405377/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does Java Object casting work behind the scene?
提问by peter
Possible Duplicate:
How does the Java cast operator work?
Java casting implementation
可能的重复:
Java 转换运算符如何工作?
Java 铸造实现
I am always wondering how object casting works in Java. I understand for primitive type it will be more like in binary representation level, but what about Object? Is it kind of like Polymorphism
or dynamic binding
in that everything will be determined at runtime? For example:
我一直想知道对象转换在 Java 中是如何工作的。我理解原始类型更像是二进制表示级别,但是对象呢?它有点像Polymorphism
或dynamic binding
一切都将在运行时确定?例如:
class Parent{
void A(){}
}
class Child extends Parent{
@Override
void A(){}
}
Parent p = new Parent();
Child c = (Child) p;
How does this work behind the scene? Does it create a new instance of Child
? And also, what happens if you try to cast:
这在幕后如何运作?它是否创建了一个新实例Child
?而且,如果您尝试投射会发生什么:
Child b = (Child) new Object();
And last one, when casting a primitive to a wrapper class:
最后一个,将原始类型转换为包装类时:
Double d = (Double) 3.3;
I know you don't necessary need to cast it, but what if you do? Is there anything significant that happens on the backend?
我知道你不需要投射它,但如果你这样做呢?后端有什么重要的事情发生吗?
回答by asteri
No new objects are created in the system when you use explicit casting (except in your last case, where you cast a primitive type to an object wrapper, since double
is not an object like Double
is). Note that this explicit cast isn't necessary due to Java's autoboxing feature.
当您使用显式转换时,系统中不会创建新对象(除了在最后一种情况下,您将原始类型转换为对象包装器,因为double
它不是像Double
is那样的对象)。请注意,由于 Java 的自动装箱功能,不需要此显式转换。
In your (Child) new Object()
scenario, you will receive a ClassCastExceptionbecause an Object
is not a Child
(although the opposite is true).
在您的(Child) new Object()
场景中,您将收到ClassCastException,因为 anObject
不是 a Child
(尽管相反是正确的)。
The answer to your first scenario is the most complicated. Essentially the parent class is treated like an interface might be. When you cast the Child
to the Parent
, only the Parent
API is available. However, the overridden method will still be called. So, if you do:
第一个场景的答案是最复杂的。本质上,父类被视为可能的接口。当您将Child
转换为 时Parent
,只有Parent
API 可用。但是,覆盖的方法仍将被调用。所以,如果你这样做:
Parent p = (Parent) new Child();
p.a();
... the Child
's public void a()
will be called, even though it is being seen through the lens of the Parent
class. However if you were to have a second method in the Child
that the Parent
does not have (let's say public void b()
for instance), you would notbe able to call that without casting the object back to a Child
.
... Child
'spublic void a()
将被调用,即使它是通过Parent
类的镜头看到的。但是,如果你有第二种方法中Child
的Parent
没有(假设public void b()
为实例),你会不会能够调用,如果没有铸造对象回Child
。
"Behind the scenes", as you say, the only new thing that is created is another object referencewhich points to the same object. You can have as many references as you like to the same, singular object. Consider this example:
正如您所说,“在幕后”创建的唯一新事物是另一个指向同一对象的对象引用。对于同一个单一对象,您可以拥有任意数量的引用。考虑这个例子:
Parent p = new Parent();
Parent p1 = p;
Parent p2 = p;
Parent p3 = p2;
Here, there are four references (p
, p1
, p2
, and p3
) each of which points to the same object you created with the new Parent()
declaration.
这里有四个引用(p
、p1
、p2
和p3
),每个引用都指向您使用new Parent()
声明创建的同一个对象。
I would probably argue on the philosophical point, though, that this creation of new references is actually explicit rather than behind the scenes when you say Parent p = something
.
不过,我可能会在哲学观点上争论,当您说Parent p = something
.
Links:
链接:
- http://en.wikipedia.org/wiki/Primitive_wrapper_class
- http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html
- http://docs.oracle.com/javase/7/docs/api/java/lang/ClassCastException.html
- http://docs.oracle.com/javase/tutorial/java/IandI/override.html
- Is Java "pass-by-reference" or "pass-by-value"?
回答by BevynQ
The simple answer to your main question is No. All casting happens at syntax checking time.
对您的主要问题的简单回答是否定的。所有转换都发生在语法检查时。
Casting affects how the syntax checker looks at the object, it does not affect the object itself, a Child cast to be a Parent, is still a Child.
转换会影响语法检查器查看对象的方式,它不影响对象本身,一个子转换为父,仍然是一个子。
However the cast is only checked at Runtime. Which is why it is dangerous and should not be used unless there is no other way.
然而,演员表只在运行时检查。这就是为什么它是危险的,除非没有其他方法,否则不应使用。
回答by OscarRyz
Accodring to this: checkcast, what it does is to verify if the reference is assignable. If it is, the stack is not changed and the operation on that reference are kept.
根据这个:checkcast,它所做的是验证引用是否可分配。如果是,则堆栈不会更改,并保留对该引用的操作。
So if you have:
所以如果你有:
Child c = ( Child ) anyObject;
c.sayHi();
If the cast success, then the method sayHi
could be invoked:
如果转换成功,则sayHi
可以调用该方法:
If objectref can be cast to the resolved class, array, or interface type, the operand stack is unchanged; otherwise, the checkcast instruction throws a ClassCastException.
如果 objectref 可以强制转换为解析的类、数组或接口类型,则操作数堆栈不变;否则,checkcast 指令会抛出 ClassCastException。
Here's the "bytecode"
这是“字节码”
$ 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
}
回答by Marko Topolnik
First of all, be very careful not to confuse conversionwith casting. They may share the surface syntax, but are very different processes.
首先,要非常小心,不要将转换与强制转换混淆。它们可能共享表面语法,但是是非常不同的过程。
In Java you can downcast an Object to any type, but at runtime you'll get a ClassCastException
if the object is not in fact compatible with the target type. This happens at the bytecode level: there is a bytecode instruction dedicated to downcasting.
在 Java 中,您可以将 Object 向下转换为任何类型,但在运行时,ClassCastException
如果该对象实际上与目标类型不兼容,您将得到一个。这发生在字节码级别:有一个字节码指令专用于向下转换。
Child c = (Child) new Object();
will unconditionally result in a ClassCastException
.
将无条件地导致ClassCastException
.
Double d = 3.3; // note: no explicit casting needed
will perform autoboxinginto an instance of Double
. So here, a new instance is actually created.
将自动装箱到Double
. 所以在这里,实际上创建了一个新实例。
A normal, successful dowcast may look like this:
一个正常的、成功的向下广播可能是这样的:
Object o = "a";
String s = (String)o;
Here, no objects are created: only the value of o
is copied into s
. The value is a reference.
在这里,没有创建对象:只有 的值o
被复制到 中s
。该值是一个参考。
回答by Tomasz Nurkiewicz
Downcasting an object is not doing anything to that object. Behind the scenes the compiler will inject checkcast
bytecode operation. If p
is not really an instance of Child
, exception will be thrown. Otherwise you basically have a (type-)safe reference to the same object with different, more specific type.
向下转换一个对象不会对该对象做任何事情。在幕后,编译器将注入checkcast
字节码操作。如果p
不是真正的 实例Child
,则会抛出异常。否则,您基本上拥有对具有不同、更具体类型的同一对象的(类型)安全引用。
Child b = (Child) new Object();
This fails with ClassCastException
. JVM compares getClass()
of new Object()
with Child.class
. Since Object.class
is not a subclass of Child.class
, exception is thrown.
这失败了ClassCastException
。JVM进行比较getClass()
的new Object()
有Child.class
。由于Object.class
不是 的子类Child.class
,因此抛出异常。
Double d = (Double) 3.3;
Here, casting isn't even necessary, this works as well: Double d = 3.3
. Behind the scenes this is translated to:
在这里,甚至不需要强制转换,这也适用:Double d = 3.3
. 在幕后,这被翻译为:
Double d = Double.valueOf(3.3);
This is known as Autoboxing.
这称为自动装箱。