ClassCastException与“无法强制转换”编译错误

时间:2013-11-10 21:17:55

标签: java inheritance casting 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();时,我立即收到了编译错误。

两个问题:

  1. 为什么上面的代码完全编译?电话似乎与Roamable无关?
  2. 为什么代码用new Phone()编译,但是不用new String()编译?

6 个答案:

答案 0 :(得分:14)

  

为什么上面的代码完全编译?电话似乎无关   Roamable给我?

是的,因为Roamable是一个可能导致运行时异常而不是编译时异常的接口,因为即使Phone没有实现Roamable,也是Phone的子类1}}可能,因此编译器无法知道它,但在运行时。

它已经在java语言规范中定义。 Check out my answer here

  

为什么代码用新的Phone()编译,但不编译   使用新的String()?

因为class Stringpublic final class包中声明为java.lang。如jls 8.1.1.2 final class部分所述:声明为final的类不能扩展,因此它不会有任何子类。因此,编译器已经知道String无法扩展:因此没有子类可以实现 interface Roamable

编辑:(回复您的以下评论)

让我们假设BA的子类,它实现了接口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

Why does this compile?

接口的引用可以在没有编译错误的情况下连接到任何对象。

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();
}