Java`final`方法:它承诺了什么?

Java`final`方法:它承诺了什么?,java,oop,final,Java,Oop,Final,在Java类中,可以将方法定义为final,以标记此方法可能不会被重写: public class Thingy { public Thingy() { ... } public int operationA() {...} /** this method does @return That and is final. */ public final int getThat() { ...} } 这一点很清楚,它可能对防止意外重写或性能有一定的作用,但这不是我的

在Java类中,可以将方法定义为
final
,以标记此方法可能不会被重写:

public class Thingy {
    public Thingy() { ... }
    public int operationA() {...}
    /** this method does @return That and is final. */
    public final int getThat() { ...}
}
这一点很清楚,它可能对防止意外重写或性能有一定的作用,但这不是我的问题

我的问题是:从面向对象的角度来看,我理解,通过定义一个方法
final
,类设计器承诺该方法将始终按照描述或暗示的方式工作。但这通常不受类作者的影响,如果方法所做的事情比只传递属性更复杂

语法约束对我来说很清楚,但在OOP意义上的含义是什么?大多数类作者在这个意义上是否正确使用了
final


一个
最终的
方法承诺什么样的“合同”

不,它不在课程作者的影响之外。您不能在派生类中重写它,因此它将执行基类作者想要的操作


值得注意的是,它建议从构造函数调用的方法应该是
final

我不确定您能否断言“final”的使用以及它如何影响软件的总体设计契约。您可以保证,没有开发人员可以通过这种方式覆盖此方法并使其合同无效。但另一方面,最终的方法可能依赖于其值由子类设置的类或实例变量,并且可以调用被覆盖的其他类方法。所以最终结果最多只能是一个很弱的保证

首先,您可以标记非抽象类
final
以及字段和方法。这样就不能对整个类进行子类化。所以,类的行为将是固定的

我同意,如果标记方法
final
调用非final方法,则不能保证它们在子类中的行为相同。如果行为确实需要固定,则必须通过惯例和仔细设计来实现。不要忘记在javadoc中定义这个概念!(java文档)

最后但并非最不重要的是,
final
关键字在Java内存模型(JMM)中具有非常重要的作用。JMM保证,要实现
final
字段的可见性,不需要进行适当的同步。例如:

class A implements Runnable {
  final String caption = "Some caption";                           

  void run() {
    // no need to synchronize here to see proper value of final field..
    System.out.println(caption);
  }
}  
最终方法承诺什么样的“合同”


从另一个角度看,任何非final方法都会隐式地保证您可以使用自己的实现重写它,并且类仍将按预期工作。当您不能保证您的类支持重写一个方法时,您应该将其设置为final

如前所述,
final
与Java方法一起使用,以标记该方法不能被覆盖(对于对象范围)或隐藏(对于静态)。这允许原始开发人员创建子类无法更改的功能,这就是它提供的全部保证

这意味着,如果该方法依赖于其他可自定义组件,如非公共字段/方法,则最终方法的功能仍然可以自定义。这是很好的,因为(使用多态性)它允许部分定制

有许多原因可以阻止某些东西进行自定义,包括:

  • 性能——一些编译器可以分析和优化操作,尤其是没有副作用的操作

  • 获取封装的数据——查看不可变对象,这些对象的属性在构建时设置,永远不应更改。或从这些属性派生的计算值。Java
    String
    类就是一个很好的例子

  • 可靠性和契约性——对象由原语(
    int
    char
    double
    等)和/或其他对象组成。在较大的对象中使用这些组件时,并非所有适用于这些组件的操作都应该是适用的,甚至是逻辑的。可以使用带有
    final
    修饰符的方法来确保。计数器类就是一个很好的例子


如果
public final int count()
方法不是
final
,我们可以这样做:

Counter c = new Counter() {   
    public int count() {
        super.count();   
        return super.count();   
    } 
}

c.count(); // now count 2
Counter c = new Counter() {
    public int count() {
        int lastCount = 0;
        for (int i = super.count(); --i >= 0; ) {
            lastCount = super.count();
        }

        return lastCount;
    }
}

c.count(); // Now double count
或者像这样:

Counter c = new Counter() {   
    public int count() {
        super.count();   
        return super.count();   
    } 
}

c.count(); // now count 2
Counter c = new Counter() {
    public int count() {
        int lastCount = 0;
        for (int i = super.count(); --i >= 0; ) {
            lastCount = super.count();
        }

        return lastCount;
    }
}

c.count(); // Now double count

好的,从技术上讲,它会像基类作者写的那样。是的,我知道最后的类——简单的例子。关于JMM的最终字段,这一点很好,不需要同步。。。嗯:这只是指“指针”,对吗?我仍然可以不同步地修改它引用的对象(好的,不是在
字符串中,而是在用户定义的类中)。但你所说的“最终不保证行为”正是我的观点。我同意,文档和设计很重要。@我想告诉你,
final
不能确保对复合对象所做更改的可见性,例如
Map
。是的,这就是我的意思。正确的。我喜欢术语“弱保证”:-)我(大部分)喜欢C++的
const
。正如在
char-const*const=“Hello”
char-const*const-addName(char-const*const-name)const
中一样,这个观点是否暗示了我最初的问题“这个最终方法将始终按照承诺的方式运行”,即我不能从最终方法内部调用任何非最终方法?因为,如果我这样做,被调用的方法可能已被重写,因此我无法保证最终方法的行为?