web-dev-qa-db-ja.com

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

私は静的メソッドで修飾子をいじくり回していて、奇妙な動作に遭遇しました。

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

以下のスニペットがあれば、うまくコンパイルできます

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

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

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

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

115
Harish

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

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

お役に立てれば。

155
NawaMan

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

これは正確には真実ではありません。サンプルコードは、BのメソッドtsがAのメソッドtsを非表示にすることを実際に意味します。したがって、厳密にオーバーライドするわけではありません。 Javaranch に説明があります。

12

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

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

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

エラーメッセージは上書きされる代わりに非表示のWordを使用すると思います...

10
Powerlord

次のことを考慮して、静的メソッドを最終的にすることを考える立場にいることがあります。

次のクラスを持つ:

_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からのものです。ただし、オブジェクトを指すポインターに応じて、AまたはBからメソッドを呼び出します。

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

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

確かにそれは何らかの形で構築されていますが、場合によっては意味があるかもしれません。

インスタンスではなく、クラスで直接静的メソッドを呼び出す必要があります-そうすれば、その問題は発生しません。また、IntelliJ IDEAは、インスタンスで静的メソッドを呼び出した場合、および静的メソッドを最終的にした場合にも警告を表示します。

5
Mathias Bader

ここで、コンパイルエラーは非常に誤解を招くものだったと思います。 「オーバーライドされたメソッドは静的なファイナルです」と言ってはいけませんが、代わりに「オーバーライドされたメソッドはファイナルです」と言っているべきです。静的修飾子はここでは無関係です。

1
BalusC

非静的メソッドとは異なり、静的メソッドは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がプレフィックスされている場合。したがって、finalキーワードは、子クラスで同じ名前のメソッドの作成を制限します。

0
Pratik Gupta

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

ただし、メソッドが最終的な場合、コンパイラはAにts()メソッドがあり、Bでオーバーライドされるべきではないことを認識します。

0
amischiefr