私は静的メソッドで修飾子をいじくり回していて、奇妙な動作に遭遇しました。
知っているように、静的メソッドはインスタンスではなくクラスに関連付けられているため、オーバーライドできません。
以下のスニペットがあれば、うまくコンパイルできます
//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です。
静的メソッドをまったくオーバーライドできないのに、なぜこれが起こるのですか?
静的メソッドはオーバーライドできませんが、非表示にすることはできます。 Bのts()
メソッドは、Aのts()
をオーバーライドしません(ポリモーフィズムの対象ではありません)が、非表示にします。 Bでts()
を呼び出す場合(A.ts()
またはB.ts()
... ts()
ではなく)、Bの1つが呼び出され、 Aではありません。これはポリモーフィズムの影響を受けないため、Aのts()
呼び出しはBの呼び出しにリダイレクトされません。
キーワードfinal
は、メソッドの非表示を無効にします。したがって、非表示にすることはできません。非表示にしようとすると、コンパイラエラーが発生します。
お役に立てれば。
静的メソッドはオーバーライドできません
これは正確には真実ではありません。サンプルコードは、BのメソッドtsがAのメソッドtsを非表示にすることを実際に意味します。したがって、厳密にオーバーライドするわけではありません。 Javaranch に説明があります。
次のことを考慮して、静的メソッドを最終的にすることを考える立場にいることがあります。
次のクラスを持つ:
_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は、インスタンスで静的メソッドを呼び出した場合、および静的メソッドを最終的にした場合にも警告を表示します。
ここで、コンパイルエラーは非常に誤解を招くものだったと思います。 「オーバーライドされたメソッドは静的なファイナルです」と言ってはいけませんが、代わりに「オーバーライドされたメソッドはファイナルです」と言っているべきです。静的修飾子はここでは無関係です。
非静的メソッドとは異なり、静的メソッドは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キーワードは、子クラスで同じ名前のメソッドの作成を制限します。
Bのts()メソッドは、Aのts()メソッドをオーバーライドするのではなく、単に別のメソッドです。 Bクラスは静的であるため、Aのts()メソッドを認識しません。したがって、Bクラスはts()という独自のメソッドを宣言できます。
ただし、メソッドが最終的な場合、コンパイラはAにts()メソッドがあり、Bでオーバーライドされるべきではないことを認識します。