web-dev-qa-db-ja.com

プライベートメソッドもfinalにできないのはなぜですか?

privatefinalを同じメソッドに追加するのは冗長ですか?

class SomeClass {

    //--snip--

    private final void doStuff()
    {
        // private work here
    }
}

privateの場合、誰もそれを上書きする方法はありませんよね?

効果がない場合にfinalキーワードを追加できるのはなぜですか? (または私は何かを逃していますか?)

46
MightyPork

基本的には、private修飾子を禁止する特別なケースを置くことは価値があると感じていなかったため、許可されています。これらのキーワードがインターフェースに含まれていても、インターフェースのメソッドをpublicとして宣言したり、インターフェースのネストされたクラスをstaticとして宣言したりするのに似ています。 finalクラスなどでfinalメソッドを宣言することもできます。

Javaは、冗長な修飾子を追加しても文句を言わないというスタンスをとっていました。彼らは一貫してそれを行います。

56
yshavit

プライベートメソッドがfinalである必要があるEdgeのケースの1つは、 SafeVarargs アノテーションが使用されている場合です。次のコードは、プライベートメソッドがfinalではないため、コンパイルされません。

@SafeVarargs
private void method(List<String>... stringLists) {
    //TODO a safe varargs operation
}
5
jaco0646

それは言語をより柔軟にしますが、言語はそれが何らかの効果を持つことを保証しません。プライベートメソッドをfinalにすることは、( [〜#〜] jit [〜#〜] )コンパイラへのヒントです。

Java言語仕様 notes それ:

メソッドをfinalと宣言して、サブクラスによるオーバーライドまたは非表示を防ぐことができます。

最終メソッドをオーバーライドまたは非表示にしようとすると、コンパイル時エラーになります。

プライベートメソッドと、最終クラス( §8.1.1.2 )内ですぐに宣言されたすべてのメソッドは、オーバーライドできないため、最終メソッドであるかのように動作します。

実行時に、マシンコードジェネレータまたはオプティマイザは、最終メソッドの本体を「インライン化」して、メソッドの呼び出しを本体のコードで置き換えることができます。インライン化プロセスは、メソッド呼び出しのセマンティクスを保持する必要があります。特に、インスタンスメソッド呼び出しのターゲットがnullの場合、メソッドがインライン化されていてもNullPointerExceptionをスローする必要があります。 Javaコンパイラは、メソッドが呼び出される前に、メソッドへの実際の引数が正しい順序で評価されていることがわかるように、例外が正しいポイントでスローされるようにする必要があります。

Wikipediaから

よくある誤解は、クラスまたはメソッドをfinalとして宣言すると、コンパイラーが呼び出される場所に直接メソッドを挿入できるため、効率が向上するというものです(インライン展開を参照)。しかし、メソッドは実行時にロードされるため、コンパイラーはこれを行うことができません。ランタイム環境とJITコンパイラーのみが、どのクラスがロードされたかを正確に認識しているため、メソッドがfinalであるかどうかにかかわらず、インライン化するタイミングを決定できるのはそれらだけです。

直接実行可能なプラットフォーム固有のマシンコードを生成するマシンコードコンパイラは例外です。静的リンクを使用する場合、コンパイラーは、コンパイル時に計算可能なメソッドと変数がインライン化されていると想定しても安全です。

4
McDowell