インターフェイスメソッドの最後の引数-要点は何ですか?


189

Javaではfinal、インターフェースメソッドで引数を定義することは完全に合法であり、実装クラスではそれに従わないでください。例:

public interface Foo {
    public void foo(int bar, final int baz);
}

public class FooImpl implements Foo {

    @Override
    public void foo(final int bar, int baz) {
        ...
    }
}

上記の例では、barbaz反対有するfinal界面VSクラスの定義。

同様にfinal、1つのクラスメソッドが別のクラスメソッドを拡張する場合でも、拡張しabstractない場合でも、制限は適用されません。

しながら、finalクラスメソッド本体内部のいくつかの実用的な値を有する、特定の任意の点が存在するfinalインターフェイスメソッドパラメータのか?


finalネイティブ型はコピーされるため、とにかく何もしません。
Paul Tomblin

11
ちょうど議論のポイントとして:私はそれを試してみましたが、2つのinterface定義がfinal引数の属性のみが異なる場合、結果の.classファイルはバイトごとに同じです(もちろんjavap -v同じ出力が生成されます)。finalちなみに、属性のみが異なる2つのクラスにも同じことが言えます。
Joachim Sauer

2
@Paul:参照型とまったく同じことを行います:引数自体が変更されるのを防ぎます(実装で使用されている場合)。
Joachim Sauer

メソッドシグネチャでは、パブリックと同じくらいの関連性があります。
Robin

2
@Deepak:あまり意味がなさそうな場合でも、あらゆる種類の質問についての実用的な例を求めているようです。私はあなたがいくつかの抽象的な思考を学ぶことを試みるべきだと思います:目の前にいくつかの実行可能なコードがない状態で問題について考えてみてください。それは長い目で見れば非常に役立ちます。
Joachim Sauer

回答:


103

それには意味がないようです。よるJava言語仕様4.12.4

変数finalを宣言すると、その値が変更されず、プログラミングエラーを回避するのに役立つドキュメントとして役立ちます。

ただし、finalメソッドパラメータの修飾子は、オーバーライドされたメソッドのシグネチャを照合するためルールでは言及されておらず、実装の本体内でのみ、呼び出し元には影響しません。また、コメントのRobinによって指摘されているようfinalに、メソッドパラメーターの修飾子は、生成されたバイトコードに影響を与えません。(これは、の他の用途には当てはまりませんfinal。)


メソッドパラメータも変数として使用できますか?それは明らかに実際に行われていますが、仕様のコンテキストですか?
mindas 2011年

11
実際の.classファイルには表示されないため、署名の照合には使用できません。コンパイラ専用です。
Robin

@mindas-JLSは、7種類の変数があると言っています。メソッドのパラメーターはリストの4番目です。
テッドホップ、2011年

3
ただし、final修飾子は実装クラスに適用されないため、ドキュメントはほとんど役に立ちません。インターフェイスのシグネチャは単純に嘘かもしれません。
Stefan Haberl、2015

Java 8言語仕様では、変数には8種類ある(7つから、ラムダパラメータが追加された)と記載されています。メソッドのパラメーターは、リストの4番目です(少なくとも、人生のいくつかは安定しているようです。:-))。
テッド・ホップ2016年

25

一部のIDEは、サブクラスに実装メソッドを挿入するときに、抽象/インターフェースメソッドのシグネチャをコピーします。

それがコンパイラに影響を与えるとは思いません。

編集:私はこれが過去に本当だったと信じていますが、現在のIDEはこれをもうやっていないと思います。


2
有効なポイント、私はこの機能が実装(または誤って左)されたとき、多くのIDEがあったとは思いませんが:-)
mindas

2
static transient分野のカテゴリーだと思います。;)
Peter Lawrey、2011年

1
抽象クラスのパブリックコンストラクタ。
Peter Lawrey、2011年

1
IntelliJはこれを行います。私のバージョンはIntelliJ IDEA 2016.1.3ビルド#IU-145.1617です。
2016年

1
@Dormouse、面白いです。AndroidStudio(3.1.4ビルド#AI-173.4907809)は:(
The Godfather

18

メソッドパラメータの最終アノテーションは、常にメソッド実装にのみ関連し、呼び出し元には関係しません。したがって、これらをインターフェイスメソッドのシグネチャで使用する実際の理由はありません。すべてのメソッドシグネチャで、最終的なメソッドパラメータを必要とする同じ一貫したコーディング標準に従う必要がない限り。それができるのは素晴らしいことです。


6

更新:以下の元の回答は質問を完全に理解せずに書かれたため、質問に直接対応していません。:)それにもかかわらず、finalキーワードの一般的な使用法を理解したいと考えている人にとって有益なものでなければなりません。

質問は、下から自分のコメントを引用したいと思います。

私は、あなたがあなた自身の実装においてそれが最終的であるかどうかを決定する自由をあなたに残すために、議論の最終性を実装することを強いられていないと信じています。

しかし、はい、finalインターフェイスで宣言できるのは奇妙に聞こえますが、実装ではそれを非最終的なものにします。次のいずれかである場合、より理にかなっています。

a。 finalキーワードは、インターフェース(抽象)メソッドの引数には許可されていません(ただし、実装で使用できます)、または
b。finalインターフェースのように引数を宣言するとfinal、実装で強制的に宣言されます(ただし、非最終の場合は強制されません)。


メソッドシグネチャがfinalパラメータを持つことができる2つの理由を考えることができます:Beansオブジェクト実際には、両方とも同じ理由ですが、コンテキストがわずかに異なります。

オブジェクト:

public static void main(String[] args) {
    StringBuilder cookingPot = new StringBuilder("Water ");
    addVegetables(cookingPot);
    addChicken(cookingPot);
    System.out.println(cookingPot.toString());
    // ^--- OUTPUT IS: Water Carrot Broccoli Chicken ChickenBroth 
    //      We forgot to add cauliflower. It went into the wrong pot.
}

private static void addVegetables(StringBuilder cookingPot) {
    cookingPot.append("Carrot ");
    cookingPot.append("Broccoli ");
    cookingPot = new StringBuilder(cookingPot.toString());
    //   ^--- Assignment allowed...
    cookingPot.append("Cauliflower ");
}

private static void addChicken(final StringBuilder cookingPot) {
    cookingPot.append("Chicken ");
    //cookingPot = new StringBuilder(cookingPot.toString());
    //     ^---- COMPILATION ERROR! It is final.
    cookingPot.append("ChickenBroth ");
}

このfinalキーワードにより、ローカルのクッキングポットを誤って作成することがなくなり、コンパイルエラーが表示されました。これにより、addChickenメソッドで取得したオリジナルの調理鍋にチキンブイヨンが確実に追加されます。これをaddVegetablesカリフラワーを失った場所と比較してください。カリフラワーが元の鍋ではなく、新しい地元の調理鍋に追加されたからです。

Beans: これはオブジェクトと同じ概念です(上記を参照)。Beanは基本的ObjectにJavaではです。ただし、Bean(JavaBeans)は、関連するデータの定義されたコレクションを格納して渡すための便利な方法として、さまざまなアプリケーションで使用されます。がaddVegetables新しいクッキングポットStringBuilderを作成してカリフラワーと一緒に捨てることでクッキングプロセスを台無しにするのと同じように、クッキングポットJavaBeanでも同じことができます。


OK。これは実際には質問に対する正しい答えではありません(インターフェイスがそう言ったとしても、インターフェイスメソッドの実装に最終引数をとるように強制されるわけではないため)が、それは理由の良い説明であるため、依然として役立ちますメソッドのパラメーターをfinalにすることは、まず始めに良い考えです。
Phil

私はあなたがあなた自身の実装においてそれが最終的であるかどうかを決定する自由をあなたに残しておくために議論の最終性を実装することを強いられていないと信じています。しかし、はい、finalインターフェイスで宣言できるのは奇妙に聞こえますが、実装ではそれを非最終的なものにします。いずれかの場合はより多くの意味を成しているだろう() finalキーワードは、インターフェース(抽象)メソッドの引数に許可されていません(ただし、実装でそれを使用することができます)、または(B)として、引数を宣言するfinalインタフェースでは、宣言することを強制するfinal実装に(ただし、非ファイナルの場合は強制されません)。
ADTC、2014年

「それは質問に対する正しい答えではありません」そうです、私が何を考えていたかはわかりません... 7月の初めの早い時間か何かだったに違いありません。:)
ADTC、2014年

2

それが最終的なものかどうかは実装の詳細なので、それは余分な詳細かもしれません。

(インターフェースでメソッド/メンバーをパブリックとして宣言するようなものです。)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.