Java的“最终”方法:它承诺了什么?

2022-08-31 07:34:22

在 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

最终方法承诺什么样的“契约”?


答案 1

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

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

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

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

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

  • 可靠性和协定 -- 对象由基元(、 、 等) 和/或其他对象组成。并非所有适用于这些组件的操作在更大的对象中使用时都应该适用,甚至应该是合乎逻辑的。带有修饰符的方法可用于确保这一点。计数器类就是一个很好的例子。intchardoublefinal


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

答案 2

最终方法承诺什么样的“契约”?

从另一个角度来看,任何非最终方法都隐式保证您可以使用自己的实现覆盖它,并且该类仍将按预期工作。当您无法保证您的类支持覆盖某个方法时,您应该将其设置为最终方法。