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

tow*_*owi 134 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() { ...}
}
Run Code Online (Sandbox Code Playgroud)

这很清楚,它可能有助于防止意外覆盖,或者表现 - 但这不是我的问题.

我的问题是:从OOP的角度来看,我理解通过定义一个方法final,类设计者承诺这个方法将始终如所描述或隐含的那样工作.但是,这通常可能超出了班级作者的影响,如果该方法所做的事情比传递财产更复杂.

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

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

Naw*_*Man 148

如上所述,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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

c.count(); // now count 2
Run Code Online (Sandbox Code Playgroud)

或类似的东西:

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
Run Code Online (Sandbox Code Playgroud)


jos*_*efx 26

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

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


Vic*_*kin 8

首先,您可以标记非抽象类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);
  }
}  
Run Code Online (Sandbox Code Playgroud)