最终类的编译器错误实例[重复]
Posted
技术标签:
【中文标题】最终类的编译器错误实例[重复]【英文标题】:Compiler error instance of final class [duplicate] 【发布时间】:2016-04-07 07:08:01 【问题描述】:以下代码编译正常:
interface Flyer
class Bat
public class App
public static void main(String[] args)
Bat b = new Bat();
if(b instanceof Flyer) System.out.println("b is a Bird");
如果我们将Bat
类设为final
,则代码无法编译:
final class Bat
如果最终类实现Flyer
,则编译正常:
final class Bat implements Flyer
有人愿意解释这背后的逻辑吗?
【问题讨论】:
【参考方案1】:当你创建类Bat
final
时,你是说这个类不能被子类化。由于Bat
没有实现接口Flyer
,因此编译器能够确定b instanceof Flyer
永远不可能是true
并引发错误。
这是在 JLS section 15.20.2 中指定的:
如果将 RelationalExpression 转换为 ReferenceType 的转换(第 15.16 节)将作为编译时错误被拒绝,则
instanceof
关系表达式同样会产生编译时错误。在这种情况下,instanceof
表达式的结果永远不会为真。
另外,来自section 15.16的关于演员表:
如果操作数的编译时类型可能永远不会根据强制转换规则(第 5.5 节)强制转换为强制转换运算符指定的类型,则会出现编译时错误。
在这种情况下,Bat
永远不能转换为 Flyer
:它不会实现它,final
确保不会有子类可以实现它。
如您所见,修复方法是:
使Bat
实现Flyer
:在这种情况下,instanceof
运算符将始终返回true
。
删除final
标识符,暗示Bat
的子类可能实现Flyer
。
【讨论】:
无论空实例的“类型”如何,null instanceof X
都不会返回 true 吗?但是我可以看到让编译器接受这一点是非常狡猾的
@Dici 实际上,null instanceof X
is always false
.
Ups...抱歉,你是对的,我什至用它来编写我所有的 equals
方法。我需要睡觉:D【参考方案2】:
好吧,如果Bat
是最终类并且它没有实现Flyer
,那么它也不能有任何可以实现Flyer
的子类,所以instanceof
永远不会返回true。在这种情况下,编译器不允许此表达式(即 (x instanceof Y)
仅在 x
有可能包含对实现或扩展 Y
的实例的引用时才允许使用)。
在您的第二个 sn-p 中,Bat
已经实现了Flyer
,因此b instanceof Flyer
将始终返回true
,无论Bat
是否是最终的。
【讨论】:
我觉得很奇怪(可能是一个糟糕的设计)如果它总是false
会发生编译错误,但如果它是总是 true
,那很好。
现在看来合乎逻辑...尽早检查总是一个好主意。
@MarounMaroun 这里有些不一致,我同意。
@MarounMaroun if (true)
和 if (false)
是一样的。第一个编译得很好,第二个会发出警告。我认为合理的是,死代码比无用的检查更糟糕。如果您编写一些将始终执行的条件代码,那很好,生活比您想象的要容易,但是如果您编写一些永远不会到达的代码,您可能会对程序的行为做出错误的假设,从而造成伤害【参考方案3】:
除了来自 JLS 的 @Tunaki 的引用之外,这在 https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.5.1 中也有明确的解释,引用相关规则:
如果 S 是
final
类(第 8.1.1 节),则 S 必须实现 T,否则会发生编译时错误。
instanceof
检查遵循引用类型转换的这些规则。
【讨论】:
以上是关于最终类的编译器错误实例[重复]的主要内容,如果未能解决你的问题,请参考以下文章