在Java中,在接口方法中定义最终参数是完全合法的,而在实现类中却不遵守,例如:

public interface Foo {
    public void foo(int bar, final int baz);
}

public class FooImpl implements Foo {

    @Override
    public void foo(final int bar, int baz) {
        ...
    }
}

在上面的例子中,bar和baz在类和接口中有相反的最终定义。

以同样的方式,当一个类方法扩展另一个类方法时,无论是否抽象,都不强制执行最终限制。

虽然final在类方法体中有一些实用价值,但为接口方法参数指定final是否有任何意义?


当前回答

有些ide在子类中插入实现方法时会复制抽象/接口方法的签名。

我不相信这对编译器有任何影响。

编辑:虽然我相信这在过去是正确的,但我认为现在的ide不再这样做了。

其他回答

方法参数的最后注释总是只与方法实现相关,而与调用者无关。因此,没有真正的理由在接口方法签名中使用它们。除非您希望在所有方法签名中遵循相同的一致编码标准,该标准要求最终的方法参数。那么能够这样做就很好了。

更新:下面的原始答案是在没有完全理解问题的情况下写的,因此没有直接解决问题:)然而,对于那些希望理解final关键字的一般用法的人来说,它必须是有信息的。

对于这个问题,我想在下面引用我自己的评论。

I believe you're not forced to implement the finality of an argument to leave you free to decide whether it should be final or not in your own implementation. But yes, it sounds rather odd that you can declare it final in the interface, but have it non-final in the implementation. It would have made more sense if either: a. final keyword was not allowed for interface (abstract) method arguments (but you can use it in implementation), or b. declaring an argument as final in interface would force it to be declared final in implementation (but not forced for non-finals).


我可以想到方法签名可以有最终参数的两个原因:bean和对象(实际上,它们都是相同的原因,只是上下文略有不同)。

对象:

public static void main(String[] args) {
    StringBuilder cookingPot = new StringBuilder("Water ");
    addVegetables(cookingPot);
    addChicken(cookingPot);
    System.out.println(cookingPot.toString());
    // ^--- OUTPUT IS: Water Carrot Broccoli Chicken ChickenBroth 
    //      We forgot to add cauliflower. It went into the wrong pot.
}

private static void addVegetables(StringBuilder cookingPot) {
    cookingPot.append("Carrot ");
    cookingPot.append("Broccoli ");
    cookingPot = new StringBuilder(cookingPot.toString());
    //   ^--- Assignment allowed...
    cookingPot.append("Cauliflower ");
}

private static void addChicken(final StringBuilder cookingPot) {
    cookingPot.append("Chicken ");
    //cookingPot = new StringBuilder(cookingPot.toString());
    //     ^---- COMPILATION ERROR! It is final.
    cookingPot.append("ChickenBroth ");
}

最后一个关键字确保我们不会意外地创建一个新的本地烹饪锅,当我们试图这样做时,会显示一个编译错误。这确保了鸡汤被添加到addChicken方法得到的原始烹饪锅中。将此与addVegetables进行比较,在addVegetables中,我们失去了花椰菜,因为它将花椰菜添加到新的本地烹饪锅中,而不是原来的锅中。

豆: 它与对象的概念相同(如上所示)。bean本质上是Java中的对象。但是,bean (JavaBeans)在各种应用程序中被用作存储和传递已定义的相关数据集合的方便方式。就像addVegetables创建一个新的烹饪锅StringBuilder并将其与花椰菜一起扔掉可能会打乱烹饪过程一样,它也可以对烹饪锅JavaBean做同样的事情。

有些ide在子类中插入实现方法时会复制抽象/接口方法的签名。

我不相信这对编译器有任何影响。

编辑:虽然我相信这在过去是正确的,但我认为现在的ide不再这样做了。

这似乎没有任何意义。根据Java语言规范4.12.4:

声明一个变量final是有用的 作为有用的文档说明其价值 会不会改变又能不能帮助避免 编程错误。

但是,方法参数上的final修饰符在用于匹配被覆盖方法的签名的规则中没有提到,它对调用者没有影响,只在实现的主体中有影响。另外,正如Robin在注释中指出的那样,方法参数的最终修饰符对生成的字节代码没有影响。(final的其他用法则不是这样。)

我相信这可能是一个多余的细节,因为它是否最终是一个实现细节。

(有点像将接口中的方法/成员声明为public。)