为我的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();
时,我立即收到了编译错误。
两个问题:
new Phone()
编译,但是不用new String()
编译?答案 0 :(得分:14)
为什么上面的代码完全编译?电话似乎无关 Roamable给我?
是的,因为Roamable
是一个可能导致运行时异常而不是编译时异常的接口,因为即使Phone
没有实现Roamable
,也是Phone
的子类1}}可能,因此编译器无法知道它,但在运行时。
它已经在java语言规范中定义。 Check out my answer here
为什么代码用新的Phone()编译,但不编译 使用新的String()?
因为class String
在public final class
包中声明为java.lang
。如jls 8.1.1.2 final class
部分所述:声明为final
的类不能扩展,因此它不会有任何子类。因此,编译器已经知道String
无法扩展:因此没有子类可以实现 interface 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
的实例,但它也是实现B
的类T
的实例。
答案 1 :(得分:3)
字符串是最终的,因此无法将其强制转换为Roamable。
答案 2 :(得分:1)
代码编译,因为编译器允许你转换为任何东西。这是程序员的明确行动,编译器假定您已经评估了风险并采取了适当的预防措施。
String
不是Roamable
的实例,因此您无法将String
的实例分配给Roamable
引用。这可以在编译时确定,因此失败。
答案 3 :(得分:1)
new Phone()
进入类Phone
,其中可以是实现Phone
的{{1}}的扩展名(就编译器而言) )。
如果您将Phone设为Roamable
类(如String),则会出现编译错误。
答案 4 :(得分:0)
一个好问题。 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的子类型。
答案 5 :(得分:0)
首先阅读java的Explicit and Implicit type casting。
从那个用户负责显式转换时,缩小对象关系,说用户知道并且很好,因为它们会因此而失去一些精度。但是仍然编译器可以检测到一些显式错误的转换并在某些时候抛出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. <BR>
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();
}