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

pkwftd7m  于 2023-05-12  发布在  Java
关注(0)|答案(7)|浏览(103)

我正在准备OCA Java SE 7 Programmer I考试,这是个新手问题。我有一个例子,我不明白。下面的代码编译,但在运行时给出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.为什么上面的代码可以编译?手机似乎与我的漫游无关?
1.为什么代码可以用new Phone()编译,但不能用new String()编译?

hjzp0vay

hjzp0vay1#

为什么上面的代码可以编译?手机似乎与我的漫游无关?
是的,因为Roamable是一个接口,它可能会导致运行时异常,但不会导致编译时异常,因为即使Phone没有实现RoamablePhone的子类也可能实现,因此编译器除了在运行时之外没有办法知道它。
它已经在Java语言规范中定义。在这里查看我的答案
为什么代码可以用new Phone()编译,但不能用new String()编译?
因为class Stringjava.lang包中声明为public final class。如**jls 8.1.1.2 final class**部分所述:声明为final的类不能被扩展,因此它没有任何子类。因此,编译器已经知道String不能被扩展:因此,不可能存在子类来实现 interfaceRoamable

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

让我们假设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类的示例,但它也是实现了TB类的示例。

mfuanj7w

mfuanj7w2#

字符串是final的,所以没有办法将其转换为可漫游的。

icnyk63a

icnyk63a3#

代码会编译,因为编译器允许强制转换为任何内容。这是程序员的一个显式操作,编译器假定您已经评估了风险并采取了适当的预防措施。
String不是Roamable的示例,因此不能将String的示例分配给Roamable引用。而这可以在编译时确定,所以它失败了。

r7xajy2e

r7xajy2e4#

new Phone()求值为类Phone,它 * 可能 * 是Phone的扩展,实现了Roamable(就编译器而言)。
如果将Phone设置为final类(如String),则会出现编译器错误。

8nuwlpux

8nuwlpux5#

问得好new Phone()绝对不是Phone的任何子类。但是这些信息丢失了,javac在那里看到的是Phone类型,而不是 exactPhone类型。
相关规范:http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.5.1
如果S是final类(§8.1.1),则S必须实现T,
可以使用以下命令修改规范
如果表达式是类示例创建表达式(§15.9),则表达式的类型必须是T的子类型。

inn6fuwd

inn6fuwd6#

首先阅读有关Explicit and Implicit type casting的java。
从那以后,用户负责显式转换,当缩小对象关系时,说用户知道并罚款,他们因此失去了一些精度。然而,编译器仍然可以检测到一些显式的错误转换,并在某个时候抛出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();
}
0s7z1bwu

0s7z1bwu7#

我想不需要太多的话。请简单地考虑下面的例子,记住***一个上级引用可以是指向它的一个子类的指针。

class Test {
   public static void main(String[] args) {
      
     class x {}
     interface z {}
     class y extends x implements z {}

     x xx = new x();
     // var q = (z)xx; // class cast exception
     xx = (new y()); // xx is kinda superior ref-type of "class y" right? It can point it.
     var qq = (z)xx;
    }
}

如果我们约束它,引用如何在正确的铸造之后引用对象?(在最后一行)

相关问题