【问题标题】: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 { } 

有人愿意解释这背后的逻辑吗?

【问题讨论】:

    标签: java


    【解决方案1】:

    当你创建类Batfinal时,你是说这个类不能被子类化。由于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 吗?但是我可以看到让编译器接受这一点是非常狡猾的
    • 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 检查遵循引用类型转换的这些规则。

    【讨论】:

      猜你喜欢
      • 2021-09-09
      • 1970-01-01
      • 2010-10-27
      • 2012-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-24
      相关资源
      最近更新 更多