最終的な静的メソッドの動作


123

私は静的メソッドを使用してモディファイヤをいじっており、奇妙な動作に遭遇しました。

ご存知のように、静的メソッドはインスタンスではなくクラスに関連付けられているため、オーバーライドできません。

だから私が以下のスニペットを持っているなら、それはうまくコンパイルします

//Snippet 1 - Compiles fine
public class A {
    static void ts() {
    }
}

class B extends A {
    static void ts() {
    }
}

しかし、クラスAの静的メソッドにfinal修飾子を含めると、コンパイルが失敗し 、Bのts()はAのts()をオーバーライドできません。オーバーライドされたメソッドはstatic finalです。

静的メソッドをまったくオーバーライドできないときになぜこれが起こるのですか?


2
奇妙に思えますが、質問に+1しますが、これまでのところ、どの回答も満足のいくものではありません。
Rakesh Juyal、2009年

1
オーバーライドされません。それはまだA.ts()にあります。
Alex Feinman、

回答:


166

静的メソッドはオーバーライドできませんが、非表示にすることができます。ts()B のメソッドはA のメソッドをオーバーライドしません(多態性の影響を受けません)ts()が、それはそれを隠します。ts()Bで呼び出す場合(NOT A.ts()またはB.ts()...だけts())、AではなくBの1つが呼び出されます。これはポリモーフィズムの対象ではないためts()、A での呼び出しがB での呼び出しにリダイレクトされることはありません。

キーワードfinalは、メソッドが非表示になるのを無効にします。そのため、それらを非表示にすることはできません。非表示にしようとすると、コンパイラエラーが発生します。

お役に立てれば。


30
おそらくあなたの答えを完了するために、正しいと思いますが、ここでの問題は基本的に悪いコンパイラエラーメッセージです:BはAのts()を非表示にできないと言う必要があります。
Sean Owen、

2
@Sean Owen:私もそう思います。「非表示」という用語はJava仕様でも使用されているので、コンパイラメッセージで使用しないでください。
NawaMan、2009年

2
なぜこれも機能なのですか?どのような状況で役立ちますか?
user253751 2015年

public class Test {final static public void main(String ... srik){System.out.println( "In main method"); ts(); } public static void ts(){Child c = new Child(); c.ts(); System.out.println( "Test ts"); }} public class Child extends Test {public static void ts(){System.out.println( "Child ts"); }}こんにちは、このシナリオで何が起こるかを説明できますか
srikanth r '20

@SeanOwen私もこれは正しいとは思いません。コンパイラはA#ts継承されており、そのようなメソッドが既にに存在するBため、同じシグネチャと異なる修飾子(final)を持つ2つのメソッドを単に持っていると、オーバーロードとして機能しないと言う必要があります。 。しかし、私はこのための簡単なメッセージを考えたいと思います
ユージーン

13

静的メソッドはオーバーライドできません

これは正確には当てはまりません。コード例は、BのメソッドtsがAのメソッドtsを非表示にすることを実際に意味します。そのため、正確にオーバーライドするわけではありません。上の上Javaranch素敵な説明があります。


4
正確ではありません。静的メソッドはオーバーライドできませんが、クラス名ではなくインスタンス参照で呼び出す場合は非表示にできます。
John Mercier

1
残念ながら、リンクは機能していません。これを修正することは可能ですか?
Mathias Bader 2017

javaranchリンクは機能していませんが、キーワードをグーグルするとコード
ランチで

デッドリンクをSundeepが投稿したリンクに置き換えて、投稿を編集しました。
MC皇帝

10

静的メソッドはインスタンスではなくクラスに属します。

A.ts()そしてB.ts()、常に別々のメソッドになります。

実際の問題は、Javaではインスタンスオブジェクトの静的メソッドを呼び出せることです。親クラスの同じシグネチャを持つ静的メソッドは、サブクラスのインスタンスから呼び出されると非表示になります。ただし、最終的なメソッドをオーバーライド/非表示にすることはできません。

あなたはエラーメッセージが上書きされる代わりに隠された単語を使用すると思うでしょう...


6

次の点を考慮して、静的メソッドをfinalにすることを考える立場にあるかもしれません。

次のクラスがあります。

class A {
    static void ts() {
        System.out.print("A");
    }
}
class B extends A {
    static void ts() {
        System.out.print("B");
    }
}

これらのメソッドを呼び出す「正しい」方法は

A.ts();
B.ts();

結果はAB次のようになりますが、インスタンスのメソッドを呼び出すこともできます。

A a = new A();
a.ts();
B b = new B();
b.ts();

その結果ABも同様です。

次のことを考えてみましょう。

A a = new B();
a.ts();

それは印刷されますA。実際にはクラスのオブジェクトを持っているので、これは驚くかもしれませんB。ただし、型の参照から呼び出すため、Aが呼び出されますA.ts()B次のコードで印刷できます:

A a = new B();
((B)a).ts();

どちらの場合も、あなたが持っているオブジェクトは実際にはクラスのものBです。ただし、オブジェクトを指すポインターに応じて、メソッドfrom Aまたはfrom を呼び出しますB

ここで、あなたがクラスの開発者でAあり、サブクラス化を許可したいとします。ただしts()、サブクラスからでも呼び出されるたびにmethodが本当に必要です。これは、サブクラスバージョンによって隠されないようにしたいことを実行します。次に、それを作成してfinal、サブクラスに隠されないようにすることができます。そして、次のコードがクラスからメソッドを呼び出すことを確認できますA

B b = new B();
b.ts();

わかりました、なんとなく構築されていますが、場合によっては意味があるかもしれません。

インスタンスではなくクラスで直接静的メソッドを呼び出さないでください。そうすると、その問題は発生しません。また、たとえばIntelliJ IDEAは、インスタンスで静的メソッドを呼び出した場合、および静的メソッドをfinalにした場合に警告を表示します。


0

Bのts()メソッドは、Aのts()メソッドをオーバーライドするのではなく、単に別のメソッドです。Bクラスは静的であるため、Aのts()メソッドを認識しません。したがって、Bクラスは、ts()という独自のメソッドを宣言できます。

ただし、メソッドがfinalの場合、コンパイラーは、Bでオーバーライドしてはならないts()メソッドがAにあることをピックアップします。


「final」が突然これらのメソッドが共存できないことを意味する理由がこれで説明されるとは思いません。あなたが言うように、「ファイナル」がなければ、問題はありません。あなたはそれがオーバーライドしていないと言いますが、問題はBがAのメソッドをオーバーライドできないことです。
Sean Owen、

確かにそうですが、BはAのメソッドts()を認識しない(「非表示」)と述べていますが、最後の修飾子は、別のメソッドを拡張するクラスからメソッドを「非表示」にしません。しかし、ええ、わかりました。
amischiefr 2009年

0

ここではコンパイルエラーがかなり誤解を招くと思います。「オーバーライドされたメソッドはstatic finalである」と言ってはなりませんが、代わりに「オーバーライドされたメソッドはfinalである」と言っているはずです。static修飾子はここでは無関係です。


1
では、Aの静的メソッドをオーバーライドするBの静的メソッドを検討しますか?
Koray Tugay 2017年

@KorayTugayコンパイラーが潜在的にオーバーライド可能なメソッドを最初に見て(静的をしばらく無視します)、ファイナルが失敗したかどうかを知りたいだけです。でもワイルドな推測
ユージーン

Balus私はこれがStackOverflowで唯一の質の低い答えだと思います。すべてのあなたの例外的な答えを考えると、これはそれらに属していません。@BalusC
Koray

@KorayTugay:当時、コメントするのに十分な評判がありませんでした:)あなたがpingを返せば、私は答えを削除します、問題ありません。
BalusC

0

非静的メソッドとは異なり、Javaでは静的メソッドをオーバーライドできません。しかし、それらは静的および非静的データメンバーのように継承されます。これが、同じ名前の非静的メソッドを親クラスに作成できない理由です。

class Writer { 
    public static void doo(){
        System.out.println("sth");
    } 
}
class Author extends Writer{ 
    public void doo(){
        System.out.println("ok"); // error overridden method is static
    }
}

final具体的な方法本体は毎回メソッドの呼び出しを実行することをキーワードを保証します。静的メソッドが同じ名前で子クラスに作成され、メソッドへの呼び出しが行われると、サブクラスのメソッドが実行されますが、親クラスの静的メソッド名の前にfinalがプレフィックスされている場合はそうではありません。 。したがって、最後のキーワードは、子クラスでの同じ名前のメソッドの作成を制限します。

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