关于oop:Java`final`方法:它有什么承诺?

Java `final` method: what does it promise?

在Java类中,可以将方法定义为EDCOX1(0),以标记该方法可能不被重写:

1
2
3
4
5
6
public class Thingy {
    public Thingy() { ... }
    public int operationA() {...}
    /** this method does @return That and is final. */
    public final int getThat() { ...}
}

很明显,这可能有助于防止意外覆盖,或者性能覆盖,但这不是我的问题。

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

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

final方法承诺什么样的"合同"?


如上所述,EDCOX1 OR 0使用Java方法来标记该方法不能被重写(对象范围)或隐藏(对于静态)。这允许原始开发人员创建子类不能更改的功能,这就是它所提供的全部保证。

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

有很多原因可以阻止某些内容可自定义,包括:

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

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

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

1
2
3
4
5
6
7
8
9
10
11
public class Counter {
    private int counter = 0;

    public final int count() {
        return counter++;
    }

    public final int reset() {
        return (counter = 0);
    }
}

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

1
2
3
4
5
6
7
8
Counter c = new Counter() {  
    public int count() {
        super.count();  
        return super.count();  
    }
}

c.count(); // now count 2

或者像这样:

1
2
3
4
5
6
7
8
9
10
11
12
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

What kind of"contract" does a final method promise?

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


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

我同意标记方法final并不能保证如果这些方法调用非最终方法,它们在子类中的行为是相同的。如果行为确实需要固定,那么必须通过惯例和精心设计来实现。别忘了在JavaDoc中要有这样的概念!(Java文档)

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

1
2
3
4
5
6
7
8
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"的使用以及它如何影响软件的总体设计合同做出任何断言。您可以保证任何开发人员都不能重写此方法并以这种方式使其合同无效。但另一方面,最终的方法可能依赖于类或实例变量,这些变量的值由子类设置,并且可以调用被重写的其他类方法。所以,最终结果至多是一个很弱的保证。


不,这不受班级作者的影响。您不能在派生类中重写它,因此它将按照基类作者的意图进行。

http://download.oracle.com/javase/tutorial/java/iandi/final.html下载

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