ClassCastException与“无法强制转换”编译错误
为我的OCA Java SE 7程序员考试,所以新手问题。 我有一个我不明白的例子问题。 以下代码编译,但在运行时给出ClassCastException:
interface Roamable { } class Phone { } public class Tablet extends Phone implements Roamable { public static void main(String... args) { Roamable var = (Roamable) new Phone(); } }
当我改变Roamable var = (Roamable) new Phone();
进入Roamable var = (Roamable) new String();
我马上收到编译错误。
两个问题:
- 为什么上面的代码完全编译? 电话似乎与Roamable无关?
- 为什么代码用
new Phone()
编译,但不用new String()
编译?
为什么上面的代码完全编译? 电话似乎与Roamable无关?
是的,因为Roamable
是一个接口,它可能会导致运行时exception而不是编译时exception,因为即使Phone
没有实现Roamable
,也可能是Phone
的子类,因此编译器无法知道它但是在运行时。
它已经在java语言规范中定义。 在这里查看我的答案 。
为什么代码用新的Phone()编译,但不用新的String()编译?
因为class String
在java.lang
包中声明为public final class
。 正如jls 8.1.1.2 final class
部分所指定的:声明为final
的类不能被扩展,因此它不会有任何子类。 因此,编译器已经知道String
不能被扩展:因此没有子类的存在可以实现接口 Roamable
编辑:(回复您的以下评论)
让我们假设B
是A
的子类,它实现了接口T
现在声明:
T t = (T)new A();
基本上与:
A aObj = new A() ; T t = (T)aObj ; // a run-time exception happen
在得出结论之前,让我们用B
的对象做同样的事情:
A aObj = new B(); T t = (T)aObj; // no exception happen.
所以,这里有超类和子类的真正原因是参考。 第二个代码示例中的aObj
类也是A
类的实例,但它也是已实现T
B
类实例。
字符串是最终的,因此无法将其转换为Roamable。
代码编译是因为编译器允许您转换为任何内容。 这是程序员的明确操作,编译器假定您已经评估了风险并采取了适当的预防措施。
String
不是Roamable
的实例,因此您无法将String
实例分配给Roamable
引用。 这可以在编译时确定,因此失败了。
new Phone()
侵入了Phone
类,它可能是实现Roamable
的Phone
的扩展(就编译器而言)。
如果你使Phone成为final
类(如String),你将得到编译器错误。
一个好问题。 new Phone()
绝对不是Phone
任何子类。 但是,这些信息丢失了,javac在那里看到了Phone
类型,而不是确切的 Phone
类型。
相关规范: http : //docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.5.1
如果S是最终类(第8.1.1节),那么S必须实现T,
规范可以修改
如果表达式是类实例创建表达式(第15.9节),则表达式的类型必须是T的子类型。
首先阅读java关于Explicit和Implicit类型转换的内容。
从那个用户负责显式转换时,缩小对象关系,说用户知道并且因为这样,他们会失去一些精度。 但是仍然编译器可以检测到一些显式的错误转换并抛出CE: Type mismatch error
在某些时候输入CE: Type mismatch error
。 除此之外,还需要运行时ClassCastException
来处理它。
编译器可以检测以下显式转换的情况。
class A {} class B {} A a = (A) new B(); //CE: Type mismatch: cannot convert from B to A B b = (B) new A(); //compilation error (CE)
interface I {} final class A {} I i = (I) new A(); //compilation error
编译器无法检测到以下显式转换的情况。
class A {} class B extends A {} A a = (A) new B(); //Fine B b = (B) new A(); //Runtime error; because compile time; //compiler wont be able to tell the reference is instance of A or B. //means this is something like below.
B b = (B) (A) new A();
任何对象都可以在没有编译错误的情况下进入任何接口。
interface I {} class A {} class B extends A implements I{} I i = (I) new A(); //Runtime error I i = (I) new B(); //Fine
为什么编译?
接口的引用可以在没有编译错误的情况下连接到任何对象。
interface I {} class A implements I {} class B {} B b = (B) getI(); //Runtime error OR B b = (B)(I)new A(); //Runtime error public I getI() { return new A(); }
- 引起:java.lang.ClassCastException:java.sql.Timestamp无法强制转换为java.sql.Date
- Android java.lang.ClassCastException:android.widget.RelativeLayout无法强制转换为android.widget.EditText
- MyClass无法强制转换为java.lang.Comparable:java.lang.ClassCastException
- readResolve无法正常工作? :出现了一个Guava的SerializedForm实例
- 如何从Object获取布尔值
- 在`Service`类中运行新的`runnableThread`时出现java.lang.ClassCastException
- Hibernate – > ArrayList不能转换为Set
- ClassCastException在Hibernate / Spring 4升级后,无法将Proxy36强制转换为SessionImplementor
- 为什么在转换为不相关的接口时会编译?