Java将对象转换为未实现的接口

我在学习书中发现了以下问题,有点困惑:

给定以下代码,如果用于替换/* INSERT CODE HERE */ ,哪个选项将启用Roamable类型的引用变量来引用Phone类的对象? (选择1个选项。)

 interface Roamable{} class Phone {} class Tablet extends Phone implements Roamable { //INSERT CODE HERE } 

选项包括:

  1. Roamable var = new Phone();
  2. Roamable var = (Roamable)Phone();
  3. Roamable var = (Roamable)new Phone();
  4. 由于接口Roamable和类Phone不相关,因此Roamable类型的引用变量不能引用Phone类的对象。

我认为正确的选项是4,但它说它是3。

但是, Phone并没有实现Roamable接口,所以你不能施展,可以吗?

正确的答案是3 :编译器只看到一个PhoneRoamable转换为Roamable并且该Phone不是final,因此它认为正在转换的对象虽然被称为Phone ,但它可能是实现RoamablePhone的子类,因此不会发出编译时错误或警告。

根据JLS第5章

5.5.1。 参考类型铸造

给定编译时引用类型S(源)和编译时引用类型T(目标),如果由于以下规则而没有发生编译时错误,则从S到T存在转换转换。 如果T是接口类型:

如果S不是最终类(第8.1.1节),那么,如果存在T的超类型X和S的超类型Y,那么X和Y都可certificate是不同的参数化类型,并且X的擦除和Y是相同的,发生编译时错误。

否则,强制转换在编译时总是合法的(因为即使S没有实现T,S的子类也可能)。

如果S是最终类(第8.1.1节),那么S必须实现T,否则会发生编译时错误。


以下代码编译:

 interface Roamable{} class Phone {} class Tablet extends Phone implements Roamable { Roamable var = (Roamable)new Phone(); // Compiles } 

答案是4

 1 is incorrect(explanation --> 4) 2 is incorrect syntax 3 is incorrect typecast. 

请注意, 答案3只要是编译就有效。 当你说你有一个Phone类的实例时,你可以输入cast到Tablet (类似于你可以将ObjectString )。 而且由于Tablet实现了Roamable你可以很好地使用Roamable引用来引用它。 Problem will occur at runtime因为Object实际上是Phone类型。

这只是一个允许成功编译的链接模式(在当前上下文中)。 但正如波希米亚人在他的答案中提到的那样

如果我们对编译时间引用S(非final)进行类型转换以编译时间引用T,那么even if S does not implement T, a subclass of S might ),编译也会成功。 如果S是最终类,那么S必须实现T,否则会发生编译时错误。

实际上根本不需要Tablet类扩展Phone类。 只要Phone类not final编译就会成功

 interface Roamable{} class Phone {} class Tablet implements Roamable { Roamable var = (Roamable)new Phone(); // Compiles }