当我定义一个接口方法的参数final时,我需要在实现中重复final吗?

Mr_*_*s_D 6 java inheritance final

所以我需要在下面的案例中重复最终决定吗?

interface Foo {

    void meth(final Bar bar);
}

public Baz implements Foo {

    @Override
    void meth(/* is it final ?*/ Bar bar){}
}
Run Code Online (Sandbox Code Playgroud)

问题不仅是接口继承,还有类继承 - 我猜答案是一样的

Raf*_*ter 7

是的,您需要重新声明方法参数,final就像您希望编译器确保在当前方法中永远不会重新分配这些参数一样.当覆盖接口和类定义时,这同时适用.

原因很简单:这是Java语言规范中指定的行为.但是,编译器甚至无法检查是否重新分配final参数,即使它想要:

final方法范围中变量的修饰符实际上并未转换为字节代码或在别处写入Java类文件格式.它在编译特定类或接口后基本消失,并且在编译后无法跟踪.由于每个类和接口都是独立于其他类和接口编译的,因此编译器或JVM运行时验证程序无法确保final在子类或接口实现中为参数分配了新值.它只在单个类的编译中,Java编译器可以确保不会发生此类分配.final因此,参数声明对于类是本地的,并且不可能在将来更改此行为或通过使用运行时反射来查找此功能.

final因此,在抽象方法签名中使用参数不会有用,无论是真实的还是纪录的:由于Java 通过值调用而不是通过引用来实现方法调用,因此final修饰符永远不会影响实现方法范围之外的代码.因此,如果重新分配方法参数变量,则仅仅是方法实际实现的细节.因此,我个人从不使用它来定义类或接口中的抽象方法.这是允许的,但没有意义.

在非抽象方法定义中,声明方法变量final仅用于以下两个目的之一:

  • 您想在匿名类的范围内使用变量.
  • 您希望编译器检查您是否意外重新分配变量.这在处理类似类型的许多变量时特别有用.这里,final修饰符也可以作为某种文档.

更新:从Java 8开始,如果方法参数是合成的(在源代码中未表示,强制要求(隐含地存在于源代码中,例如thislambda表达式的引用)或者是否合成,则归因于方法参数final.但这不会影响重写方法final需要重复声明才能设置此标志.此外,Java语言没有注意这些标志,只有元框架才能读取这些标志来实现可能对这些标志作出反应的逻辑.

  • @alfasin:我认为"必须"在界面中的`final`与实现没有关系(因为它是多余的),所以如果你想让编译器在实现上强制实现不变性,你需要`最终`那里也是. (2认同)
  • 这个问题没有其他答案.那我在哪里复制答案呢?即使我从其他地方拿走了这个答案,如果我提供尽可能完整的答案,那会不会很好?完成JLS后,您可能会阅读有关堆栈溢出的一些信息.我将首先以骄傲的方式对堆栈溢出进行首次投票. (2认同)