Java 转换接口到类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3582804/
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
Java Casting Interface to Class
提问by komenan
public class InterfaceCasting {
private static class A{}
public static void main(String[] args) {
A a = new A();
Serializable serializable = new Serializable(){};
a = (A)serializable;
}
}
Compilation succeed but Runtime exception
编译成功但运行时异常
Exception in thread "main" java.lang.ClassCastException: InterfaceCasting cannot be cast to InterfaceCasting$A
WHY COMPILATION SUCCEED? Compiler must known that serialiazable is not A?
为什么编译成功?编译器一定知道serialiazable不是A?
回答by u290629
Serializable
is NOT an A
, so it throws ClassCastException
.
Serializable
不是A
,所以它抛出ClassCastException
.
回答by cherouvim
It can't know that because the compile time type of serializable
is Serializable
.
它无法知道,因为 的编译时类型serializable
是Serializable
.
To illustrate, consider this:
为了说明,请考虑:
private static class A{}
private static class B implements Serializable {}
Serializable serializable = new B();
A a = (A)serializable;
this is exactly like your question, it compiles.
这与您的问题完全一样,它可以编译。
private static class A{}
private static class B implements Serializable {}
B b = new B();
A a = (A)b;
this does not compile because b
is not an A
.
这不会编译,因为b
它不是A
.
回答by aioobe
As you point out, this willcompile:
正如您所指出的,这将编译:
interface MyInterface {}
class A {}
public class InterfaceCasting {
public static void main(String[] args) {
MyInterface myObject = new MyInterface() {};
A a = (A) myObject;
}
}
Thishowever, will notcompile:
但是,这不会编译:
interface MyInterface {}
class A {}
public class InterfaceCasting {
public static void main(String[] args) {
A a = (A) new MyInterface() {}; // javac says: "inconvertible types!"
}
}
So, what's going on here? What's the difference?
那么,这里发生了什么?有什么不同?
Well, since MyInterface
is simply an interface, it couldvery well be implemented by a class that extends A, in which case the cast from MyInterface
to A
would be legal.
好吧,因为MyInterface
它只是一个接口,所以它可以很好地由扩展 A 的类实现,在这种情况下,从MyInterface
to的强制转换A
将是合法的。
This code for instance, will succeed in 50% of all executions, and illustrates that the compiler would need to solve possibly undecidable problems in order to always "detect" illegal casts at compile time.
例如,这段代码将在所有执行的 50% 中成功,并说明编译器需要解决可能无法确定的问题,以便在编译时始终“检测”非法强制转换。
interface MyInterface {}
class A {}
class B extends A implements MyInterface {}
public class InterfaceCasting {
public static void main(String[] args) {
MyInterface myObject = new MyInterface() {};
if (java.lang.Math.random() > 0.5)
myObject = new B();
A a = (A) myObject;
}
}
回答by Amarghosh
Serializable serializable;
a = (A)serializable;
As for the compiler, the variable serializable can contain any object that implements Serializable
, which includes subclasses of A
. So it assumes that you know that the variables indeed contains an A
object and allows that line.
对于编译器,变量可序列化可以包含实现 的任何对象Serializable
,其中包括 的子类A
。所以它假设您知道变量确实包含一个A
对象并允许该行。
回答by Kris
The compiler is not smart enough to trace the origins of serializable
and realize that it can never be of type A
. It really only evaluates the line:
编译器不够聪明,无法追踪 的起源serializable
并意识到它永远不会是 类型A
。它实际上只评估该行:
a = (A)serializable;
and sees that serializable
a reference of type Serializable
but it may reference a class that alsois of type A
. The actual class that serializable
references is not known until run-time.
并看到serializable
一个 type 的引用,Serializable
但它可能引用一个也是type 的类A
。serializable
直到运行时才知道引用的实际类。
In this trivial case, we know that this cast will never succeed, but in general this is left as a run-time issue as the different code paths that may lead to a casting are (in theory) infinite.
在这种微不足道的情况下,我们知道这个转换永远不会成功,但一般来说,这将作为一个运行时问题,因为可能导致转换的不同代码路径(理论上)是无限的。
If you want to avoid this issue at run-time you could test for it..
如果你想在运行时避免这个问题,你可以测试它..
if (serializable instanceof A) {
a = (A)serializable;
} else ....
回答by Sean Patrick Floyd
While I don't know the correct answer, it's usually not a good idea to cast an interface to a class, for several reasons.
虽然我不知道正确答案,但出于多种原因,将接口转换为类通常不是一个好主意。
a) An interface defines a contract, it guarantees behavior. A class may define more than this contract, usage of the other methods may have unexpected side-effects and break APIs. E.g. when a method is passed a list and you find out the passed object is actually a LinkedList and you cast it and use the Queue based methods it also defines, you are breaking the API.
a) 一个接口定义了一个契约,它保证了行为。一个类可能定义的不仅仅是这个契约,其他方法的使用可能会产生意想不到的副作用并破坏 API。例如,当一个方法被传递一个列表并且你发现传递的对象实际上是一个 LinkedList 并且你转换它并使用它也定义的基于队列的方法时,你正在破坏 API。
b) also, the object with the interface may not be a "real" object at runtime, but perhaps a service proxy created around the original object by a library such as Spring or EJB. Your cast will fail in those cases.
b) 此外,具有接口的对象在运行时可能不是“真实”对象,而可能是由诸如 Spring 或 EJB 之类的库围绕原始对象创建的服务代理。在这些情况下,您的演员表将失败。
If you absolutely must cast, never do it without an instanceof check:
如果您绝对必须强制转换,请不要在没有 instanceof 检查的情况下执行此操作:
if(myServiceObject instanceof MyServiceObjectImpl){
MyServiceObjectImpl impl = (MyServiceObjectImpl) myServiceObject;
}
回答by Colin Hebert
The detailed rules for compile-time legality of a casting conversion of a value of compile-time reference type S to a compile-time reference type T are as follows:
[...]
If S is an interface type:
- If T is an array type, [...].
- If T is a type that is not final (§8.1.1), then if there exists a supertype X of T, and a supertype Y of S, such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs. Otherwise, the cast is always legal at compile time (because even if T does not implement S, a subclass of T might).
将编译时引用类型 S 的值强制转换为编译时引用类型 T 的编译时合法性的详细规则如下:
[...]
如果 S 是接口类型:
- 如果 T 是数组类型,[...]。
- 如果 T 是非最终类型(第 8.1.1 节),则如果存在 T 的超类型 X 和 S 的超类型 Y,则 X 和 Y 都是可证明不同的参数化类型,并且擦除X 和 Y 相同,则发生编译时错误。否则,转换在编译时总是合法的(因为即使 T 没有实现 S,T 的子类也可能)。
Source :
JLS : Conversions and Promotions
资料来源:
JLS:转换和促销
回答by Andreas Dolk
Java language specificationstates, that:
Java 语言规范指出:
Some casts can be proven incorrect at compile time; such casts result in a compile-time error.
有些强制转换在编译时可能被证明是不正确的;这种强制转换会导致编译时错误。
And later on the show The detailed rules for compile-time legality of a casting conversion of a value of compile-time reference type S to a compile-time reference type T- beware, they are very complex and hard to understand.
稍后在节目中将编译时引用类型 S 的值转换为编译时引用类型 T 的编译时合法性的详细规则- 请注意,它们非常复杂且难以理解。
The interesting rule is:
有趣的规则是:
- If Sis an interfacetype:
- If Tis a type that is not final(§8.1.1), then if there exists a supertype X of T, and a supertype Y of S, such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs. Otherwise, the cast is always legal at compile time (because even if T does not implement S, a subclass of T might).
- 如果S是接口类型:
- 如果T是非最终类型(第 8.1.1 节),则如果存在 T 的超类型 X 和 S 的超类型 Y,使得 X 和 Y 都是可证明不同的参数化类型,并且X 和 Y 相同,发生编译时错误。否则,转换在编译时总是合法的(因为即使 T 没有实现 S,T 的子类也可能)。
In your example, it's perfectly clear, that the cast is illegal. But consider this slight change:
在您的示例中,很明显,演员阵容是非法的。但是考虑一下这个细微的变化:
public class InterfaceCasting {
private static class A{}
private static class B extends A implements Serializable{}
public static void main(String[] args) {
A a = new A();
Serializable serializable = new B(){};
a = (A)serializable;
}
}
Now a cast from a Serializable
to A
is possible at runtime and this shows, that in those cases, it's better left to the runtime to decide if we can cast or not.
现在可以在运行时从 aSerializable
进行A
转换,这表明,在这些情况下,最好由运行时决定我们是否可以转换。