在Java类中,可以将方法定义为final
,以标记此方法可能不会被覆盖:
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
方法承诺什么样的“合同”?
答案 0 :(得分:143)
如上所述,final
与Java方法一起使用,以标记该方法不能被覆盖(对于对象范围)或隐藏(对于静态)。这允许原始开发人员创建无法通过子类更改的功能,这是它提供的所有保证。
这意味着如果该方法依赖于其他可自定义的组件(如非公共字段/方法),则最终方法的功能仍可以自定义。这很好,但是(使用多态)它允许部分定制。
有许多理由可以防止某些内容被自定义,包括:
性能 - 有些编译器可以分析和优化操作,尤其是没有副作用的操作。
获取封装数据 - 查看不可变对象,其属性在构造时设置,不应更改。或者从这些属性派生的计算值。一个很好的例子是Java String
类。
可靠性和合同 - 对象由基元(int
,char
,double
等)和/或其他对象组成。并非所有适用于这些组件的操作都应适用,或者在更大的对象中使用时也应该是合乎逻辑的。使用final
修饰符的方法可用于确保。 Counter类就是一个很好的例子。
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
,我们可以这样做:
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
答案 1 :(得分:23)
最终方法承诺什么样的“合同”?
从另一个角度来看,任何非最终方法都会使隐式保证可以使用您自己的实现覆盖它,并且该类仍将按预期工作。当你不能保证你的班级支持覆盖一个方法时,你应该把它作为最终的。
答案 2 :(得分:8)
首先,您可以标记非抽象类final
以及字段和方法。这样整个类不能被子类化。因此,课程的行为将得到修复。
我同意标记方法final
不保证如果这些方法调用非final方法,它们在子类中的行为将是相同的。如果确实需要修复行为,则必须通过惯例和精心设计来实现。并且不要忘记在javadoc中使用它!(java文档)
最后但并非最不重要的是,final
关键字在Java内存模型(JMM)中起着非常重要的作用。 JMM保证,为了实现final
字段的可见性,您不需要进行适当的同步。 E.g:
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);
}
}
答案 3 :(得分:0)
不,这不受班级作者的影响。您不能在派生类中覆盖它,因此它将执行基类作者所期望的操作。
http://download.oracle.com/javase/tutorial/java/IandI/final.html
值得注意的是,它表明从构造函数调用的方法应该是final
。
答案 4 :(得分:0)
我不确定您是否可以对“最终”的使用做出任何断言,以及它如何影响软件的整体设计合同。您可以保证没有开发人员可以覆盖此方法并以此方式使其合同无效。但另一方面,final方法可能依赖于其值由子类设置的类或实例变量,并且可以调用 重写的其他类方法。所以决赛最多是一个非常弱的保证。