静的メソッドをオーバーライドできないのはなぜですか?
可能であれば、例を使用してください。
Parent p = new Child()
、その後、p.childOverriddenStaticMethod()
コンパイラはそれを解決しますParent.childOverriddenStaticMethod()
参照型を調べることで。
静的メソッドをオーバーライドできないのはなぜですか?
可能であれば、例を使用してください。
Parent p = new Child()
、その後、p.childOverriddenStaticMethod()
コンパイラはそれを解決しますParent.childOverriddenStaticMethod()
参照型を調べることで。
回答:
オーバーライドは、クラスのインスタンスがあるかどうかに依存します。ポリモーフィズムのポイントは、クラスをサブクラス化でき、それらのサブクラスを実装するオブジェクトは、スーパークラスで定義された(およびサブクラスでオーバーライドされた)同じメソッドに対して異なる動作をすることです。静的メソッドはクラスのインスタンスに関連付けられていないため、この概念は適用されません。
これに影響を与えるJavaの設計を推進する2つの考慮事項がありました。1つはパフォーマンスに関する懸念でした。Smalltalkが遅すぎる(ガベージコレクションとポリモーフィックコールがその一部である)との批判が多く、Javaの作成者はそれを回避しようと決心しました。もう1つは、Javaの対象読者がC ++開発者であるという決定でした。静的メソッドを機能させる方法は、C ++プログラマーにとってなじみ深いという利点があり、また、どのメソッドを呼び出すかを実行時まで把握するためにランタイムまで待つ必要がないため、非常に高速でした。
obj.staticMethod()
)から静的メソッドを呼び出すときに発生します。これは許可されており、コンパイル時の型を使用します。静的呼び出しがクラスの非静的メソッド内にある場合、「現在の」オブジェクトはクラスの派生型である可能性がありますが、派生型で定義された静的メソッドは考慮されません(これらはランタイム型にあります)階層)。
個人的には、これはJavaの設計上の欠陥だと思います。はい、はい。静的メソッドがクラスなどにアタッチされているときに、非静的メソッドがインスタンスにアタッチされていることを理解しています。それでも、次のコードを検討してください。
public class RegularEmployee {
private BigDecimal salary;
public void setSalary(BigDecimal salary) {
this.salary = salary;
}
public static BigDecimal getBonusMultiplier() {
return new BigDecimal(".02");
}
public BigDecimal calculateBonus() {
return salary.multiply(getBonusMultiplier());
}
/* ... presumably lots of other code ... */
}
public class SpecialEmployee extends RegularEmployee {
public static BigDecimal getBonusMultiplier() {
return new BigDecimal(".03");
}
}
このコードは期待どおりに機能しません。つまり、SpecialEmployeeは、正社員と同じように2%のボーナスを受け取ります。しかし、「静的」を削除すると、SpecialEmployeeには3%のボーナスが与えられます。
(確かに、この例はコーディングスタイルが悪いので、現実には、ボーナスマルチプライヤをハードコードするのではなく、データベースのどこかに配置する必要があります。ポイントに関係のないコードの)。
あなたがgetBonusMultiplierを静的にしたいと思うことは私にはかなりもっともらしく思えます。おそらく、各カテゴリに従業員のインスタンスがなくても、従業員のすべてのカテゴリのボーナス乗数を表示できるようにしたいとします。そのような例のインスタンスを検索するポイントは何ですか?従業員の新しいカテゴリを作成していて、まだ従業員が割り当てられていない場合はどうなりますか?これは、論理的には静的関数です。
しかし、それは機能しません。
そして、はい、はい、上記のコードを書き換えて機能させる方法はいくつでも考えられます。私の要点は、それが解決できない問題を作成することではなく、不注意なプログラマーの罠を作成することです。なぜなら、言語は私が合理的な人が期待するように動作しないからです。
おそらく私がOOP言語用のコンパイラーを書こうとした場合、静的関数をオーバーライドできるようにそれを実装することが困難または不可能である理由がすぐにわかります。
あるいは、Javaがこのように動作する理由がいくつかあるのかもしれません。誰かがこの動作の利点を指摘できますか?これによって簡単になる問題のカテゴリがありますか?つまり、私にJava言語仕様を指摘するだけでなく、「参照してください。これはその動作方法が文書化されています」と言っているのではありません。そんなこと知ってる。しかし、それがこのように振る舞うべきである正当な理由はありますか?(明白な「それを正しく機能させるのは大変でした」以外に...)
更新
@VicKirk:Javaが静的を処理する方法に適合しないため、これが「悪い設計」であるということを意味する場合、私の返事は「まあ、もちろんです」です。元の投稿で述べたように、機能しません。しかし、これが機能した言語、つまり静的関数が仮想関数のようにオーバーライドされる可能性のある言語に根本的に何か問題があるという意味で設計が悪いことを意味する場合、これはどういうわけか曖昧さをもたらすか、またはそれを不可能にするでしょう効率的に実装するなどして、「なぜ?コンセプトの何が悪いの?」
私が挙げる例は、やりたいことは非常に自然なことだと思います。インスタンスデータに依存しない関数を持つクラスがあり、インスタンスから独立して呼び出したい場合や、インスタンスメソッド内から呼び出したい場合があります。なぜこれはうまくいかないのですか?私はこの状況に何年にもわたって何度も遭遇しました。実際には、関数を仮想化し、ダミーのインスタンスを使用して仮想メソッドに呼び出しを渡す静的メソッドを唯一の目的とする静的メソッドを作成することで回避します。それはそこに行くための非常に回り道のようです。
someStatic()
あり、BがAを拡張している場合、AのメソッドにB.someMethod()
バインドします。その後someStatic()
Bに追加した場合、呼び出し元のコードA.someStatic()
を再コンパイルするまで呼び出し元のコードが引き続き呼び出されます。また、リンクではなくコンパイル時にバインドするため、ランタイムタイプではなく、bInstance bInstance.someStatic()
の宣言されたタイプを使用していることに驚きましたA bInstance; ... bInstance.someStatic()
。B.someStatic()が存在する場合、A.someStatic()を呼び出します。
簡単に言えば、それは完全に可能ですが、Javaはそれを行いません。
以下は、Javaの現状を示すコードです。
ファイルBase.java
:
package sp.trial;
public class Base {
static void printValue() {
System.out.println(" Called static Base method.");
}
void nonStatPrintValue() {
System.out.println(" Called non-static Base method.");
}
void nonLocalIndirectStatMethod() {
System.out.println(" Non-static calls overridden(?) static:");
System.out.print(" ");
this.printValue();
}
}
ファイルChild.java
:
package sp.trial;
public class Child extends Base {
static void printValue() {
System.out.println(" Called static Child method.");
}
void nonStatPrintValue() {
System.out.println(" Called non-static Child method.");
}
void localIndirectStatMethod() {
System.out.println(" Non-static calls own static:");
System.out.print(" ");
printValue();
}
public static void main(String[] args) {
System.out.println("Object: static type Base; runtime type Child:");
Base base = new Child();
base.printValue();
base.nonStatPrintValue();
System.out.println("Object: static type Child; runtime type Child:");
Child child = new Child();
child.printValue();
child.nonStatPrintValue();
System.out.println("Class: Child static call:");
Child.printValue();
System.out.println("Class: Base static call:");
Base.printValue();
System.out.println("Object: static/runtime type Child -- call static from non-static method of Child:");
child.localIndirectStatMethod();
System.out.println("Object: static/runtime type Child -- call static from non-static method of Base:");
child.nonLocalIndirectStatMethod();
}
}
これを実行すると(私はMacで、Eclipseから、Java 1.6を使用して)、次のようになります。
Object: static type Base; runtime type Child.
Called static Base method.
Called non-static Child method.
Object: static type Child; runtime type Child.
Called static Child method.
Called non-static Child method.
Class: Child static call.
Called static Child method.
Class: Base static call.
Called static Base method.
Object: static/runtime type Child -- call static from non-static method of Child.
Non-static calls own static.
Called static Child method.
Object: static/runtime type Child -- call static from non-static method of Base.
Non-static calls overridden(?) static.
Called static Base method.
ここで、驚きかもしれない(そして質問がそうである)唯一のケースが最初のケースであるように見えます:
「ランタイムタイプは、オブジェクトインスタンス(obj.staticMethod()
)で呼び出された場合でも、呼び出される静的メソッドを決定するために使用されません。」
そして最後のケース:
「クラスのオブジェクトメソッド内から静的メソッドを呼び出す場合、選択される静的メソッドは、オブジェクトのランタイム型を定義するクラスからではなく、クラス自体からアクセスできるメソッドです。」
静的呼び出しはコンパイル時に解決されますが、非静的メソッド呼び出しは実行時に解決されます。静的メソッドは(親から)継承されますが、(子によって)オーバーライドされないことに注意してください。予想外の場合、これは驚きかもしれません。
オブジェクトメソッドの呼び出しは、ランタイム型を使用して解決されますが、静的(クラス)メソッドの呼び出しは、コンパイル時(宣言)型を使用して解決されます。
これらのルールを変更して、呼び出された例の最後の呼び出しでChild.printValue()
、コンパイラーがオブジェクトの宣言されたクラス(または環境)。次に、静的呼び出しは、(動的)型階層を使用して、今日のオブジェクトメソッド呼び出しと同様に、呼び出しを解決できます。
これは簡単に実行でき(Java:-Oを変更した場合)、まったく不合理ではありませんが、いくつかの興味深い考慮事項があります。
主な考慮事項は、どの静的メソッド呼び出しでこれを実行するかを決定する必要があることです。
現時点では、Javaにはこの「癖」があり、呼び出しは(通常は警告付きで)obj.staticMethod()
呼び出しに置き換えられObjectClass.staticMethod()
ます。[ 注: ObjectClass
はのコンパイル時の型ですobj
。]これらは、このようにオーバーライドして、ランタイム型のを取得するのに適した候補ですobj
。
これを行うと、メソッド本体が読みにくくなります。親クラスの静的呼び出しは、動的に「再ルーティング」される可能性があります。これを回避するには、静的メソッドをクラス名で呼び出す必要があります。これにより、(現在のように)コンパイル時の型階層で呼び出しがより明確に解決されます。
静的メソッドを呼び出す他の方法は、よりトリッキーです。ランタイムタイプをthis.staticMethod()
とすると、と同じ意味になるはずobj.staticMethod()
ですthis
。ただし、これにより、装飾なしで(おそらくローカルな)静的メソッドを呼び出す既存のプログラムで頭痛の種になる可能性があります(これはおそらくと同等ですthis.method()
)。
では、無人の通話はstaticMethod()
どうですか?今日と同じようにして、ローカルクラスコンテキストを使用して何をすべきかを決定することをお勧めします。そうでなければ、大きな混乱が起こります。もちろん、それmethod()
がthis.method()
if method
が非静的メソッドであり、かつThisClass.method()
if method
が静的メソッドだったということを意味します。これも混乱の原因です。
この動作を変更した場合(および静的呼び出しを動的に非ローカルにする可能性がある場合)は、クラスのメソッドの修飾子としてfinal
、private
およびクラスのメソッドのprotected
修飾子として再検討したいと思うでしょうstatic
。メソッドprivate static
とpublic final
メソッドがオーバーライドされないため、コンパイル時に安全に解決でき、ローカル参照として「安全」に読み取ることができることに慣れる必要があります。
実際、私たちは間違っていました。
Javaではデフォルトで静的メソッドをオーバーライドすることはできませんが、JavaのClassおよびMethodクラスのドキュメントを徹底的に調べれば、次の回避策で静的メソッドのオーバーライドをエミュレートする方法を見つけることができます。
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
class RegularEmployee {
private BigDecimal salary = BigDecimal.ONE;
public void setSalary(BigDecimal salary) {
this.salary = salary;
}
public static BigDecimal getBonusMultiplier() {
return new BigDecimal(".02");
}
public BigDecimal calculateBonus() {
return salary.multiply(this.getBonusMultiplier());
}
public BigDecimal calculateOverridenBonus() {
try {
// System.out.println(this.getClass().getDeclaredMethod(
// "getBonusMultiplier").toString());
try {
return salary.multiply((BigDecimal) this.getClass()
.getDeclaredMethod("getBonusMultiplier").invoke(this));
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
return null;
}
// ... presumably lots of other code ...
}
final class SpecialEmployee extends RegularEmployee {
public static BigDecimal getBonusMultiplier() {
return new BigDecimal(".03");
}
}
public class StaticTestCoolMain {
static public void main(String[] args) {
RegularEmployee Alan = new RegularEmployee();
System.out.println(Alan.calculateBonus());
System.out.println(Alan.calculateOverridenBonus());
SpecialEmployee Bob = new SpecialEmployee();
System.out.println(Bob.calculateBonus());
System.out.println(Bob.calculateOverridenBonus());
}
}
結果の出力:
0.02
0.02
0.02
0.03
私たちが達成しようとしていたこと:)
3番目の変数CarlをRegularEmployeeとして宣言し、それにSpecialEmployeeのインスタンスを割り当てたとしても、最初のケースではRegularEmployeeメソッドの呼び出しがあり、2番目のケースではSpecialEmployeeメソッドの呼び出しがあります。
RegularEmployee Carl = new SpecialEmployee();
System.out.println(Carl.calculateBonus());
System.out.println(Carl.calculateOverridenBonus());
出力コンソールを見てください:
0.02
0.03
;)
静的メソッドはJVMによってグローバルとして扱われ、オブジェクトインスタンスにまったくバインドされていません。
(Smalltalkのような言語のような)クラスオブジェクトから静的メソッドを呼び出すことができれば、概念的には可能かもしれませんが、Javaではそうではありません。
編集
静的メソッドをオーバーロードできます。ただし、クラスはファーストクラスのオブジェクトではないため、静的メソッドをオーバーライドすることはできません。リフレクションを使用して、実行時にオブジェクトのクラスを取得できますが、取得するオブジェクトはクラス階層に対応していません。
class MyClass { ... }
class MySubClass extends MyClass { ... }
MyClass obj1 = new MyClass();
MySubClass obj2 = new MySubClass();
ob2 instanceof MyClass --> true
Class clazz1 = obj1.getClass();
Class clazz2 = obj2.getClass();
clazz2 instanceof clazz1 --> false
クラスを振り返ることはできますが、そこで止まります。を使用して静的メソッドを呼び出すのではなくclazz1.staticMethod()
、を使用しMyClass.staticMethod()
ます。静的メソッドは、オブジェクトにバインドされていないとの概念したがって存在しないthis
にもsuper
静的メソッドでは。静的メソッドはグローバル関数です。結果として、ポリモーフィズムの概念もないため、メソッドのオーバーライドは意味がありません。
しかしMyClass
、Smalltalkのように、メソッドを呼び出す実行時のオブジェクトである場合(または、JRubyのコメントの1つが示唆しているが、JRubyについては何も知らない場合)は、この可能性があります。
そうそう...もう一つ。オブジェクトを介して静的メソッドを呼び出すことはできますobj1.staticMethod()
が、これは本当に構文上の問題でMyClass.staticMethod()
あり、避ける必要があります。最近のIDEでは通常、警告が表示されます。彼らがこのショートカットを許可した理由を私は知りません。
clazz2 instanceof clazz1
適切にあなたの代わりに使用することができclass2.isAssignableFrom(clazz1)
、私はあなたの例ではtrueを返すと信じています、。
メソッドのオーバーライドは、動的ディスパッチングによって可能になります。つまり、オブジェクトの宣言されたタイプによって動作が決定されるのではなく、ランタイムタイプが決定されます。
Animal lassie = new Dog();
lassie.speak(); // outputs "woof!"
Animal kermit = new Frog();
kermit.speak(); // outputs "ribbit!"
lassie
との両方kermit
がtypeのオブジェクトとして宣言されている場合でも、動的ディスパッチングは、コンパイル時ではなく実行時にメソッド呼び出しを実装にのみバインドするためAnimal
、それらの動作(メソッド.speak()
)は異なります。.speak()
ここで、static
キーワードが意味を持ち始めるところです。「静的」という単語は「動的」の反意語です。したがって、静的メソッドをオーバーライドできないのは、静的メンバーに動的ディスパッチがないためです。静的とは、文字通り「動的ではない」という意味です。それらが動的にディスパッチされた場合(したがってオーバーライドされる可能性がある場合)、static
キーワードはもはや意味をなさなくなります。
はい。実際には、Javaは静的メソッドをオーバーライドできます。理論的には、Javaで静的メソッドをオーバーライドすると、コンパイルと実行はスムーズに行われますが、Javaの基本的なプロパティであるポリモーフィズムは失われます。自分でコンパイルして実行することは不可能であることを、どこでも読むことができます。あなたはあなたの答えを得るでしょう。たとえば、Animalクラスと静的メソッドeat()があり、その静的メソッドをサブクラスでオーバーライドすると、Dogと呼ばれます。次に、Dogオブジェクトを動物参照に割り当て、Javaに従ってeat()を呼び出す場合はいつでも、Dogのeat()が呼び出されているはずですが、静的オーバーライド動物ではeat()が呼び出されます。
class Animal {
public static void eat() {
System.out.println("Animal Eating");
}
}
class Dog extends Animal{
public static void eat() {
System.out.println("Dog Eating");
}
}
class Test {
public static void main(String args[]) {
Animal obj= new Dog();//Dog object in animal
obj.eat(); //should call dog's eat but it didn't
}
}
Output Animal Eating
Javaのポリモーフィズム原則によれば、出力はになりますDog Eating
。
しかし、ポリモーフィズムをサポートするためにJavaはレイトバインディングを使用するため、結果は異なりました。つまり、メソッドは実行時にのみ呼び出され、静的メソッドの場合には呼び出されません。静的メソッドでは、コンパイラは実行時ではなくコンパイル時にメソッドを呼び出すため、参照に従ってメソッドを取得します。オブジェクトではなく参照を含むメソッドを取得します。そのため、実際には静的オーバーリングをサポートしていますが、理論的にはそうですない
オーバーライドは、インスタンスのメンバーが多態的な動作をサポートするために予約されています。静的クラスのメンバーは特定のインスタンスに属していません。代わりに、静的メンバーはクラスに属し、サブクラスは保護されたインスタンスメンバーとパブリックインスタンスメンバーのみを継承し、静的メンバーは継承しないため、オーバーライドはサポートされません。別のアプローチを評価するために、インターフェースおよび研究工場や戦略設計パターンを定義することができます。
Java(および多くのOOP言語ですが、すべてを話すことはできません。一部はまったく静的ではありません)では、すべてのメソッドに固定のシグニチャー(パラメーターとタイプ)があります。仮想メソッドでは、最初のパラメーターが暗黙的に含まれています。オブジェクト自体への参照であり、オブジェクト内から呼び出されると、コンパイラーは自動的にを追加しますthis
。
静的メソッドに違いはありません-それらはまだ固定された署名を持っています。ただし、静的メソッドを宣言することにより、コンパイラーは暗黙のオブジェクトパラメーターをそのシグニチャーの先頭に含めてはならないことを明示的に述べました。したがって、これを呼び出す他のコードでは、オブジェクトへの参照をスタックに配置してはなりません。それを行った場合、パラメータがスタック上の間違った場所(1つシフト)にあるため、メソッドの実行は機能しません。
この2つの違いにより、仮想メソッドは常にコンテキストオブジェクト(つまりthis
)への参照を持っているので、オブジェクトのそのインスタンスに属するヒープ内の任意のものを参照できます。ただし、静的メソッドでは、渡される参照がないため、コンテキストが不明であるため、そのメソッドはオブジェクト変数やメソッドにアクセスできません。
Javaが定義を変更してオブジェクトコンテキストが静的または仮想のすべてのメソッドに渡されるようにしたい場合は、基本的に仮想メソッドのみを使用します。
誰かがオペレーションへのコメントで尋ねたように-この機能が必要な理由と目的は何ですか?
Rubyについてはあまり知りません。これはOPで言及されていたので、調査を行いました。Rubyのクラスは本当に特別な種類のオブジェクトであり、(動的であっても)新しいメソッドを作成できることがわかります。クラスはRubyでは完全なクラスオブジェクトであり、Javaではありません。これは、Java(またはC#)で作業するときに受け入れる必要があるものです。これらは動的言語ではありませんが、C#はいくつかの形式の動的言語を追加しています。実際には、Rubyには私が見つけられる限り「静的」メソッドはありません。その場合、これらはシングルトンクラスオブジェクトのメソッドです。次に、このシングルトンを新しいクラスでオーバーライドできます。前のクラスオブジェクトのメソッドは、新しいクラスで定義されたメソッドを呼び出します(正しい?)。したがって、元のクラスのコンテキストでメソッドを呼び出した場合でも、元の静的オブジェクトのみが実行されます。ただし、派生クラスのメソッドを呼び出すと、親クラスまたはサブクラスからメソッドが呼び出されます。おもしろいですし、それに価値があると思います。それは別の思考パターンを取ります。
Javaで作業しているので、その方法で調整する必要があります。なぜ彼らはこれをしたのですか?おそらく、利用可能なテクノロジーと理解に基づいて、当時のパフォーマンスを改善するためでしょう。コンピュータ言語は常に進化しています。十分に前に戻ると、OOPのようなものはありません。将来的には、他にも新しいアイデアがあります。
編集:もう1つのコメント。違いがわかり、Java / C#開発者自身も、Rubyのような言語を使用している場合にJava開発者からの回答が混乱する理由を理解できます。Java static
メソッドはRuby class
メソッドと同じではありません。Java開発者はこれを理解するのに苦労します。逆に、Ruby / Smalltalkのような言語で主に作業する人は逆です。Javaも静的メソッドについて語る別の方法として「クラスメソッド」を使用しているが、Rubyではこの同じ用語が異なる方法で使用されているという事実によって、これがどのように非常に混乱するかもわかります。JavaにはRubyスタイルのクラスメソッドがありません(申し訳ありません)。RubyにはJavaスタイルの静的メソッドはありません。これは、Cで見られるような、古いスタイルの関数にすぎません。
ちなみに、質問ありがとうございます!今日、クラスメソッド(Rubyスタイル)について新しいことを学びました。
まあ... Javaでオーバーライドされたメソッドがどのように動作するかという観点から考えると、答えはNOです。ただし、静的メソッドをオーバーライドしようとしても、コンパイラエラーは発生しません。つまり、オーバーライドしようとしても、Javaはそれを止めません。ただし、非静的メソッドの場合と同じ効果は得られません。Javaでのオーバーライドとは、特定のメソッドが、オブジェクトのコンパイル時のタイプではなく、オブジェクトの実行時のタイプに基づいて呼び出されることを意味します(オーバーライドされた静的メソッドの場合)。さて...なぜ彼らが奇妙な振る舞いをするのかについての推測はありますか?これらはクラスメソッドであるため、それらへのアクセスは常に、コンパイル時に、コンパイル時の型情報のみを使用して解決されます。
例:静的メソッドをオーバーライドしようとするとどうなるか見てみましょう:-
class SuperClass {
// ......
public static void staticMethod() {
System.out.println("SuperClass: inside staticMethod");
}
// ......
}
public class SubClass extends SuperClass {
// ......
// overriding the static method
public static void staticMethod() {
System.out.println("SubClass: inside staticMethod");
}
// ......
public static void main(String[] args) {
// ......
SuperClass superClassWithSuperCons = new SuperClass();
SuperClass superClassWithSubCons = new SubClass();
SubClass subClassWithSubCons = new SubClass();
superClassWithSuperCons.staticMethod();
superClassWithSubCons.staticMethod();
subClassWithSubCons.staticMethod();
// ...
}
}
出力:-
SuperClass: inside staticMethod
SuperClass: inside staticMethod
SubClass: inside staticMethod
出力の2行目に注目してください。staticMethodがオーバーライドされた場合、ランタイムタイプのオブジェクトで「SuperClass」ではなく「SubClass」として「staticMethod()」を呼び出しているため、この行は3行目と同じである必要があります。これにより、静的メソッドは常にコンパイル時の型情報のみを使用して解決されることが確認されます。
通常、静的メソッドの「オーバーライド」を許可しても、実行時に呼び出すメソッドを決定する適切な方法がないため、意味がありません。Employeeの例で、RegularEmployee.getBonusMultiplier()を呼び出すと、どのメソッドが実行されることになっていますか?
Javaの場合、オブジェクトのインスタンスを通じて呼び出される限り、静的メソッドを「オーバーライド」できる言語定義を想像できます。ただし、これでできることは、通常のクラスメソッドを再実装して、言語に冗長性を追加するだけで、実際には何の利点もありません。
オーバーライドすることで、オブジェクトタイプに応じて多態性を作成できます。静的メソッドはオブジェクトと関係がありません。したがって、Javaは静的メソッドのオーバーライドをサポートできません。
私はジェイのコメントが好きで倍増します(https://stackoverflow.com/a/2223803/1517187)。
これはJavaの悪い設計であることに同意します。
他の多くの言語は、以前のコメントで見たように、静的メソッドのオーバーライドをサポートしています。ジェイも私と同じようにDelphiからJavaにやってきたと感じています。
Delphi(Object Pascal)は、OOPを実装した最初の言語でした。
過去には商用GUI製品を作成するための唯一の言語だったため、多くの人々がその言語の経験を持っていることは明らかです。そして-はい、Delphiで静的メソッドをオーバーライドできます。実際には、Delphiの静的メソッドは「クラスメソッド」と呼ばれていますが、Delphiには「Delphi静的メソッド」という異なる概念があり、アーリーバインディングが使用されています。レイトバインディングを使用する必要があったメソッドをオーバーライドするには、「仮想」ディレクティブを宣言します。とても便利で直感的で、Javaでこれを期待していました。
静的メソッドをオーバーライドすることで何ができるでしょうか。インスタンスを介して静的メソッドを呼び出すことはできません。
MyClass.static1()
MySubClass.static1() // If you overrode, you have to call it through MySubClass anyway.
編集:残念ながら言語設計の見落としにより、インスタンスを通じて静的メソッドを呼び出すことができるようです。一般的には誰もそれをしません。私の悪い。
variable.staticMethod()
代わりにを呼び出すことが許可される理由です。私はそれが悪い言語設計であることに同意します。Class.staticMethod()
variable
Class
Javaでのオーバーライドとは、特定のメソッドがオブジェクトのコンパイル時の型ではなく、オブジェクトの実行時の型に基づいて呼び出されることを意味します(オーバーライドされた静的メソッドの場合)。静的メソッドはクラスメソッドであるため、インスタンスメソッドではないため、静的メソッドの性質上、特定のクラスに属しているため、どの参照がどのオブジェクトまたはインスタンスを指しているかとは関係ありません。サブクラスで再宣言することはできますが、そのサブクラスは、親クラスの静的メソッドについては何も知りません。これは、すでに述べたように、宣言されているクラスにのみ固有であるためです。オブジェクト参照を使用してそれらにアクセスすることは、Javaの設計者によって与えられた追加の自由であり、詳細と例を制限する場合にのみ、そのプラクティスを停止することは考えるべきではありません。 http://faisalbhagat.blogspot.com/2014/09/method-overriding-and-method-hiding.html
オーバーライドすることで、動的なポリモーフィズムを実現します。静的メソッドをオーバーライドすると言うと、使用しようとしている単語は矛盾しています。
静的は言う-コンパイル時、オーバーライドは動的なポリモーフィズムに使用されます。どちらも性質が逆なので、一緒に使用することはできません。
プログラマーがオブジェクトを使用してインスタンスメソッドにアクセスすると、動的なポリモーフィックな動作が発生します。JREは、使用しているオブジェクトの種類に基づいて、さまざまなクラスのさまざまなインスタンスメソッドをマップします。
静的メソッドをオーバーライドすると言うと、静的メソッドは、コンパイル時にリンクされるクラス名を使用してアクセスするため、実行時にメソッドを静的メソッドにリンクするという概念はありません。したがって、「オーバーライドする」静的メソッド自体は意味を持ちません。
注:オブジェクトを使用してクラスメソッドにアクセスする場合でも、Javaコンパイラはそれを見つけるのに十分なほどインテリジェントであり、静的リンクを行います。
Box.createBox
が、static はに比べて意味がありBoxFactory.createBox
、例外をスローせずにエラーチェックの構築が必要な場合は避けられないパターンです(コンストラクタは失敗せず、プロセス/スローのみを終了できます)例外)一方、静的メソッドは失敗時にnullを返すか、hastebin.com / codajahati.javaのようなものを書き込むために成功/エラーコールバックを受け入れることさえできます。
この質問の答えは簡単です。静的としてマークされたメソッドまたは変数はクラスにのみ属します。そのため、静的メソッドはスーパークラスにのみ属しているため、サブクラスで継承できません。
簡単な解決策:シングルトンインスタンスを使用します。オーバーライドと継承が可能になります。
私のシステムでは、渡されたClassのインスタンスを返すSingletonsRegistryクラスがあります。インスタンスが見つからない場合は作成されます。
Haxe言語クラス:
package rflib.common.utils;
import haxe.ds.ObjectMap;
class SingletonsRegistry
{
public static var instances:Map<Class<Dynamic>, Dynamic>;
static function __init__()
{
StaticsInitializer.addCallback(SingletonsRegistry, function()
{
instances = null;
});
}
public static function getInstance(cls:Class<Dynamic>, ?args:Array<Dynamic>)
{
if (instances == null) {
instances = untyped new ObjectMap<Dynamic, Dynamic>();
}
if (!instances.exists(cls))
{
if (args == null) args = [];
instances.set(cls, Type.createInstance(cls, args));
}
return instances.get(cls);
}
public static function validate(inst:Dynamic, cls:Class<Dynamic>)
{
if (instances == null) return;
var inst2 = instances[cls];
if (inst2 != null && inst != inst2) throw "Can\'t create multiple instances of " + Type.getClassName(cls) + " - it's singleton!";
}
}
Singleton.get()
。レジストリは単なる定型的なオーバーヘッドであり、クラスのGCを排除します。
静的メソッド、変数、ブロック、またはネストされたクラスは、オブジェクトではなくクラス全体に属します。
Javaのメソッドは、オブジェクト/クラスの動作を公開するために使用されます。ここで、メソッドは静的であるため(つまり、静的メソッドはクラスの動作のみを表すために使用されます。)クラス全体の動作を変更/オーバーライドすると、オブジェクト指向プログラミングの基本的な柱の1つである現象(つまり、高い凝集性)に違反します。。(コンストラクターはJavaの特別な種類のメソッドであることを忘れないでください。)
凝集度が高い-1つのクラスは1つの役割のみを持つ必要があります。例:車クラスは車オブジェクトのみを生成し、自転車、トラック、飛行機などは生成しません。ただし、車クラスには、それ自体にのみ属するいくつかの機能(動作)がある場合があります。
したがって、Javaプログラミング言語を設計している間。言語デザイナーは、メソッドの性質を静的にすることによってのみ、開発者がクラスのいくつかの動作をそれ自体に保つことができると考えていました。
以下のピースコードは静的メソッドをオーバーライドしようとしますが、コンパイルエラーは発生しません。
public class Vehicle {
static int VIN;
public static int getVehileNumber() {
return VIN;
}}
class Car extends Vehicle {
static int carNumber;
public static int getVehileNumber() {
return carNumber;
}}
これは、ここではメソッドをオーバーライドしていないが、再宣言しているだけだからです。Javaではメソッドの再宣言が可能です(静的/非静的)。
CarクラスのgetVehileNumber()メソッドからstaticキーワードを削除すると、コンパイルエラーが発生します。これは、Vehicleクラスにのみ属する静的メソッドの機能を変更しようとしているためです。
また、getVehileNumber()がfinalとして宣言されている場合、コードはコンパイルされません。final キーワードは、プログラマがメソッドを再宣言することを制限するためです。
public static final int getVehileNumber() {
return VIN; }
全体として、静的メソッドをどこで使用するかはソフトウェア設計者次第です。個人的には、静的メソッドを使用して、クラスのインスタンスを作成せずにいくつかのアクションを実行することを好みます。第二に、クラスの振る舞いを外の世界から隠すこと。
ここに簡単な説明があります。静的メソッドはクラスに関連付けられ、インスタンスメソッドは特定のオブジェクトに関連付けられます。オーバーライドにより、特定のオブジェクトに関連付けられたオーバーライドされたメソッドのさまざまな実装を呼び出すことができます。したがって、オブジェクトに関連付けられていない静的メソッドをオーバーライドするのは直観に反しますが、そもそもクラス自体はオーバーライドされます。そのため、静的メソッドは、それを呼び出しているオブジェクトに基づいてオーバーライドすることはできません。静的メソッドは、それが作成されたクラスに常に関連付けられます。
public abstract IBox createBox();
内部IBoxインターフェースを使用することは、どのように直観に反していますか?BoxはIBoxを実装してcreateBoxをオーバーライドし、オブジェクトの作成結果を有効なIBoxにできます。それ以外の場合はnullを返します。コンストラクタは「null」を返すことができないため、(1)EVERYWHERE(今行っていること)の例外を使用するか、(2)先ほど言ったことを行うが、初心者やエキスパートには意味をなさない方法でファクトリクラスを作成する必要がありますJavaの(私たちも今やっている)。静的な実装されていないメソッドはこれを解決します。
上記の回答を見ると、静的メソッドをオーバーライドできないことは誰もが知っていますが、サブクラスから静的メソッドにアクセスする概念について誤解しないでください。
この静的メソッドがサブクラスで定義された新しい静的メソッドによって隠されていない場合、サブクラス参照を使用してスーパークラスの静的メソッドにアクセスできます。
例については、以下のコードを参照してください:
public class StaticMethodsHiding {
public static void main(String[] args) {
SubClass.hello();
}
}
class SuperClass {
static void hello(){
System.out.println("SuperClass saying Hello");
}
}
class SubClass extends SuperClass {
// static void hello() {
// System.out.println("SubClass Hello");
// }
}
出力:-
SuperClass saying Hello
サブクラスで静的メソッドを非表示にする方法の詳細については、 JavaのOracleドキュメントを参照し、サブクラスで実行できることを検索してください。
ありがとう
次のコードは、それが可能であることを示しています。
class OverridenStaticMeth {
static void printValue() {
System.out.println("Overriden Meth");
}
}
public class OverrideStaticMeth extends OverridenStaticMeth {
static void printValue() {
System.out.println("Overriding Meth");
}
public static void main(String[] args) {
OverridenStaticMeth osm = new OverrideStaticMeth();
osm.printValue();
System.out.println("now, from main");
printValue();
}
}
osm
はありOverridenStaticMeth
ませんOverrideStaticMeth
。