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。

当您将class
Bat
设为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
    方法。我需要睡一觉