web-dev-qa-db-ja.com

Java `final`メソッド:それは何を約束しますか?

Javaクラスでは、メソッドをfinalに定義して、このメソッドがオーバーライドされないようにすることができます。

public class Thingy {
    public Thingy() { ... }
    public int operationA() {...}
    /** this method does @return That and is final. */
    public final int getThat() { ...}
}

それは明らかであり、偶発的な上書きやパフォーマンスからの保護に役立つかもしれませんが、それは私の質問ではありません。

私の質問は:OOPの観点から、メソッドfinalを定義することにより、クラスデザイナーpromisesがこのメソッドが常に説明または暗黙に機能することを理解しました。しかし、メソッドが何をしているのかがプロパティーを単に配信するよりも複雑である場合、これはクラス作成者の影響の外にあることがよくあります。

構文上の制約は私には明らかですが、OOPの意味にはどのような意味がありますか?この意味で、ほとんどのクラス作成者はfinalを正しく使用していますか?

finalメソッドはどのような「契約」を約束しますか?

133
towi

前述のように、finalはJavaメソッドとともに使用され、メソッドをオーバーライド(オブジェクトスコープの場合)または非表示(静的の場合)できないことを示します。これにより、元の開発者は、サブクラスでは変更できない機能を作成でき、それがすべての保証となります。

つまり、メソッドが非パブリックフィールド/メソッドなどの他のカスタマイズ可能なコンポーネントに依存している場合、最終メソッドの機能はカスタマイズ可能です。ただし、(ポリモーフィズムを使用して)部分的なカスタマイズが可能であるため、これは良いことです。

何かがカスタマイズできないようにする理由はいくつかあります。

  • パフォーマンス-一部のコンパイラーは、特に副作用のない操作を分析および最適化できます。

  • カプセル化されたデータを取得する-構築時に属性が設定され、変更すべきではない不変オブジェクトを調べます。または、これらの属性から派生した計算値。良い例は、Java Stringクラスです。

  • 信頼性と契約-オブジェクトは、プリミティブ(intchardoubleなど)および/または他のオブジェクトで構成されます。これらのコンポーネントに適用可能なすべての操作が、より大きなオブジェクトで使用される場合に適用可能または論理的である必要はありません。 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
144
NawaMan

最終メソッドはどのような「契約」を約束しますか?

別の方法で見ると、非最終メソッドは暗黙の保証になり、独自の実装でオーバーライドでき、クラスは引き続き期待どおりに動作します。クラスがメソッドの上書きをサポートしていることを保証できない場合は、メソッドをfinalにする必要があります。

24
josefx

まず、非抽象クラスfinalおよびフィールドとメソッドをマークできます。この方法では、クラス全体をサブクラス化することはできません。したがって、クラスの動作は修正されます。

メソッドfinalをマークしても、これらのメソッドが非最終メソッドを呼び出している場合、それらの動作がサブクラスで同じになることを保証しないことに同意します。動作を実際に修正する必要がある場合は、慣習と慎重な設計によってこれを達成する必要があります。また、javadocでこのことを忘れないでください!(Javaドキュメント)

最後になりましたが、finalキーワードは、Java Memory Model(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);
  }
}  
8
Victor Sorokin

いいえ、それはクラス作成者の影響外ではありません。派生クラスでそれをオーバーライドすることはできません。したがって、基本クラスの作成者が意図したことを行います。

http://download.Oracle.com/javase/tutorial/Java/IandI/final.html

注目に値するのは、コンストラクターから呼び出されるメソッドはfinalであることを示唆する部分です。

0
Brian Roach

「最終」の使用と、それがソフトウェアの設計契約全体にどのように影響するかについて、あなたが主張できるかどうかはわかりません。開発者がこのメソッドをオーバーライドして、その方法でそのコントラクトを無効にできないことが保証されます。しかし一方で、最終メソッドは、サブクラスによって値が設定されるクラス変数またはインスタンス変数に依存し、areオーバーライドされる他のクラスメソッドを呼び出すことができます。そのため、finalはせいぜい非常に弱い保証です。

0
Jim Ferrans