Java 最终类的编译器错误实例
以下代码编译得很好:Java 最终类的编译器错误实例,java,Java,以下代码编译得很好: 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
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 { }
有人想解释一下这背后的逻辑吗 好吧,如果
Bat
是一个最终类,并且它没有实现Flyer
,那么它也不能有任何子类实现Flyer
,因此instanceof
永远不能返回true。在这种情况下,编译器不允许使用此表达式(即(x instanceof Y)
仅在x
可能包含对实现或扩展Y
的实例的引用时才允许使用)
在您的第二个代码段中,
Bat
已经实现了Flyer
,因此b Flyer
的instanceof总会返回true
,无论Bat
是否为final。当您将classBat
设为final时,您是在说这个类不能被细分。由于Bat
没有实现接口Flyer
,编译器能够确定Flyer的b实例永远不能true
,并引发错误
这在JLS中有规定:
如果RelationalExpression对ReferenceType的强制转换(§15.16)将作为编译时错误被拒绝,则
关系表达式的实例同样会产生编译时错误。在这种情况下,instanceof
表达式的结果永远不可能为真
此外,从关于强制转换表达式:
如果根据强制转换规则(§5.5),操作数的编译时类型可能永远不会强制转换为强制转换运算符指定的类型,则为编译时错误
在这种情况下,Bat
永远不能转换为Flyer
:它不实现它,并且final
确保不会有子类实现它
如您所知,修复程序包括:
- 使
Bat
执行Flyer
:在这种情况下,
操作符的实例将始终返回true
删除final
标识符,这意味着可能有Bat
的子类实现Flyer
除了JLS中@Tunaki的引用外,还引用了相关规则在中进行了明确解释:
如果S是最终类(§8.1.1),则S必须实现T,否则会发生编译时错误。
instanceof
检查遵循引用类型强制转换的这些规则。我觉得奇怪(可能是一个糟糕的设计),如果总是false,就会发生编译错误,但如果总是true
,那么就可以了。现在看起来似乎合乎逻辑了。。。提前检查总是一个好主意。@marounnaroun这里有一些不一致的地方,我同意。@marounnaroun对于if(true)
和if(false)
也是一样的。第一个编译得很好,第二个发出警告。我认为理性的观点是,死代码比无用的检查更糟糕。如果你写了一些总是可以执行的条件代码,很好,生活比你想象的要简单,但是如果你写了一些永远不会达到的代码,你可能会对你的程序的行为做出错误的假设,这可能会造成伤害,不管“类型”如何,都不会返回true空实例的名称?然而,我可以看出,让编译器接受这一点是非常狡猾的that@Dici实际上,.Ups。。。对不起,你说得对,我甚至用它来写我所有的equals
方法。我需要睡一觉