接口方法中的最终参数 - 有什么意义?

发布于 2024-10-24 17:56:56 字数 515 浏览 6 评论 0原文

在Java中,在接口方法中定义final参数是完全合法的,但在实现类中不遵守该参数,例如:

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) {
        ...
    }
}

在上面的示例中,barbaz 在类与接口中具有相反的final 定义。

同样,当一个类方法扩展另一个类方法(无论是否抽象)时,不会强制执行任何 final 限制。

虽然 final 在类方法体内有一些实用价值,但为接口方法参数指定 final 有什么意义吗?

In Java, it is perfectly legal to define final arguments in interface methods and do not obey that in the implementing class, e.g.:

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) {
        ...
    }
}

In the above example, bar and baz has the opposite final definitions in the class VS the interface.

In the same fashion, no final restrictions are enforced when one class method extends another, either abstract or not.

While final has some practical value inside the class method body, is there any point specifying final for interface method parameters?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

梦毁影碎の 2024-10-31 17:56:56

似乎没有任何意义。根据 Java 语言规范 4.12 .4

声明一个变量final即可
作为有用的文档表明其价值
不会改变并且可以帮助避免
编程错误。

但是,匹配重写方法签名的规则,它对调用者没有影响,仅在实现主体内。此外,正如 Robin 在评论中指出的那样,方法参数上的 final 修饰符对生成的字节代码没有影响。 (对于 final 的其他用途而言,情况并非如此。)

It doesn't seem like there's any point to it. According to the Java Language Specification 4.12.4:

Declaring a variable final can serve
as useful documentation that its value
will not change and can help avoid
programming errors.

However, a final modifier on a method parameter is not mentioned in the rules for matching signatures of overridden methods, and it has no effect on the caller, only within the body of an implementation. Also, as noted by Robin in a comment, the final modifier on a method parameter has no effect on the generated byte code. (This is not true for other uses of final.)

自由范儿 2024-10-31 17:56:56

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

我不认为这对编译器有任何影响。

编辑:虽然我相信过去确实如此,但我认为当前的 IDE 不再这样做了。

Some IDEs will copy the signature of the abstract/interface method when inserting an implementing method in a sub class.

I don't believe it makes any difference to the compiler.

EDIT: While I believe this was true in the past, I don't think current IDEs do this any more.

难得心□动 2024-10-31 17:56:56

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

Final annotations of method parameters are always only relevant to the method implementation never to the caller. Therefore, there is no real reason to use them in interface method signatures. Unless you want to follow the same consistent coding standard, which requires final method parameters, in all method signatures. Then it is nice to be able to do so.

峩卟喜欢 2024-10-31 17:56:56

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

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

我相信您不会被迫实现参数的最终性,以便让您可以自由地决定在您自己的实现中它是否应该是最终的。

但是,是的,您可以在接口中将其声明为final,但在实现中将其声明为非final,这听起来很奇怪。如果有以下任一情况,那就更有意义了:

a. final 关键字不允许用于接口(抽象)方法参数(但您可以在实现中使用它),或者
b. 在接口中将参数声明为 final 将强制其在实现中声明为 final(但对于非 Final 则不强制)​​。< /p>


我可以想到方法签名可以有 final 参数的两个原因:BeansObjects实际上,它们都是相同的原因,但上下文略有不同。

对象:

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 ");
}

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

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

Update: Original answer below was written without fully understanding the question, and therefore does not directly address the question :) Nevertheless, it must be informative for those looking to understand the general use of final keyword.

As for the question, I would like to quote my own comment from below.

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).


I can think of two reasons why a method signature can have final parameters: Beans and Objects (Actually, they are both the same reason, but slightly different contexts.)

Objects:

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 ");
}

The final keyword ensured that we will not accidentally create a new local cooking pot by showing a compilation error when we attempted to do so. This ensured the chicken broth is added to our original cooking pot which the addChicken method got. Compare this to addVegetables where we lost the cauliflower because it added that to a new local cooking pot instead of the original pot it got.

Beans:
It is the same concept as objects (as shown above). Beans are essentially Objects in Java. However, beans (JavaBeans) are used in various applications as a convenient way to store and pass around a defined collection of related data. Just as the addVegetables could mess up the cooking process by creating a new cooking pot StringBuilder and throwing it away with the cauliflower, it could also do the same with a cooking pot JavaBean.

江湖彼岸 2024-10-31 17:56:56

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

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

I believe it may be a superfluous detail, as whether it's final or not is an implementation detail.

(Sort of like declaring methods/members in an interface as public.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文