【问题标题】:Final keyword in method signatures [duplicate]方法签名中的最终关键字[重复]
【发布时间】:2011-11-26 03:23:03
【问题描述】:

可能重复:
Final arguments in interface methods - what’s the point?

在尝试做一些实验时,我遇到了this page 中描述的问题。

interface B {
    public int something(final int a);
}

abstract class C {
    public int other(final int b);
}

class A extends C implements B {

    public int something(int a) {
        return a++;
    }

    public int other(int b) {
        return b++
    }
}

为什么会有这样的功能?我不知道为什么可以通过重写方法将最终参数变为非最终参数。为什么在方法签名中忽略 final 关键字?以及如何强制子类在其方法中使用最终变量?

【问题讨论】:

  • final 不是方法签名的一部分。子类的方法如何实现它与接口无关。

标签: java final method-signature


【解决方案1】:

Java 按值将参数传递给方法。

因此,对参数的任何更改都不会传播回调用者。因此,参数是否声明为final 对调用者绝对没有影响。因此,它是方法的实现的一部分,而不是其接口的一部分。

您希望“强制子类在其方法中使用最终变量”的动机是什么?

【讨论】:

  • 对我来说它确实有所作为。我不想在调用者方法中更改我的变量。必须不惜一切代价保留它的原始价值。
  • 这是一个原始变量;它是按值传递的,因此默认情况下受到保护。将对象引用声明为 final 绝不会保护该对象的内容不被修改。
  • 它将被保留,因为 Java 总是在将值传递给方法之前对其进行复制。如果方法改变了参数值,它会改变一个副本,调用者方法的值将永远不受影响,无论是否使用final。
  • 是的,我弄错了。在处理了这么多对象之后,因此它传递了对象“指针”的副本,我完全忘记了原始变量和最终类,如 Integer。无论是原始值还是 Final 类,我都不必担心,因为会保留原始值。谢谢所有回答的人!
  • "Java 按值将参数传递给方法。"仅当它们是原始的时。对象参数以指针样式传递,指针本身按值传递。因此,您可以在对象参数上调用 mutator 方法(如果您愿意,甚至可以使用反射),调用者将看到这些更改。调用者唯一看不到的是重新分配,因为您正在重新分配副本,而不是他的副本。
【解决方案2】:

final 仅用于参数意味着不能在方法主体内更改值。这不是方法签名的一部分,与子类无关。

接口或抽象方法中有final参数应该是无效的,因为它没有意义。

【讨论】:

  • "在接口或抽象方法中有final参数应该是无效的,因为它没有意义。"是的,它应该,是的,它毫无意义,但它不是无效。 :-)
【解决方案3】:

最终变量是唯一可以在闭包中使用的变量。所以如果你想做这样的事情:

void myMethod(int val) {
    MyClass cls = new MyClass() {
        @override
        void doAction() {
            callMethod(val);  // use the val argument in the anonymous class - closure!
        }
    };
    useClass(cls);
}

这不会编译,因为编译器要求 val 是最终的。所以将方法签名更改为

void myMethod(final int val)

将解决问题。局部 final 变量也可以:

void myMethod(int val) {
    final int val0;
    // now use val0 in the anonymous class

【讨论】:

    【解决方案4】:

    Java 的 final 不是 C++ const; Java 中没有 const-correctness 这样的东西。

    在 Java 中,使用不可变类来实现 const-ness。事实证明它非常有效,因为与 C++ 不同,不能简单地弄乱内存。 (您可以使用Field.setAccessible(true),然后使用反射。但即使是这种损坏向量也可以通过使用适当配置的安全管理器运行 JVM 来防止。)

    【讨论】:

    • 我认为“真正时髦的东西”是指“反思”? foo.getClass().getDeclaredField("bar").setAccessible(true) 是你所需要的,在一个无关紧要的虚拟机上。
    • 仅当您没有启用安全管理器时。在我领导的团队中,我们总是根据具体情况安装安全管理器并将访问违规列入白名单。相比之下,C++ 无法阻止(甚至检测)库将垃圾写入内存。
    • 您确实说过在不安全的虚拟机上,因此没有安全管理器。
    • 我明白你的意思。编辑答案。
    【解决方案5】:

    参数的final关键字不是方法签名的一部分,只对方法体很重要,因为Java按值传递所有参数(总是为方法调用制作一个值的副本)。

    如果编译器强制我将其设为 final,我只使用 final 关键字(用于参数),因为参数是在方法中定义的匿名类中使用的。

    【讨论】:

      【解决方案6】:

      在 Java 中,参数是按值传递的。参数是否为最终参数不仅影响该方法,而不影响调用者。我不明白为什么一个类需要指定子类型。

      【讨论】:

        【解决方案7】:

        请注意,final 参数有一个主要用途:您不能为它们分配新值。

        还要注意,参数总是按值传递的,因此调用者不会在方法内看到对参数的任何赋值。

        如果您真的想强制参数为最终参数(以防止意外重新分配参数时可能引入的错误)​​,请使用代码分析器,例如 checkstyle。

        【讨论】:

          猜你喜欢
          • 2017-01-18
          • 2010-11-04
          • 1970-01-01
          • 2013-01-30
          • 2013-05-05
          • 1970-01-01
          • 2021-10-08
          • 2019-04-14
          • 1970-01-01
          相关资源
          最近更新 更多