web-dev-qa-db-ja.com

なぜJavaは静的メソッドのオーバーライドを許可しないのですか?

静的メソッドをオーバーライドできないのはなぜですか?

可能であれば、例を使ってください。

492
sgokhales

オーバーライドはクラスのインスタンスを持つことに依存します。多態性のポイントは、クラスをサブクラス化できることです。そして、それらのサブクラスを実装するオブジェクトは、スーパークラスで定義された同じメソッドに対して異なる動作をします(そしてサブクラスでオーバーライドされます)。静的メソッドはクラスのどのインスタンスにも関連付けられていないため、この概念は適用されません。

これに影響を与えたJavaの設計を推進する2つの考慮事項がありました。パフォーマンスに対する懸念がありました。Smalltalkが遅すぎる(ガベージコレクションとポリモーフィック呼び出しがその一部である)という批判が多くあり、Javaの作成者はそれを避けようと決心しました。もう1つは、Javaの対象読者がC++開発者であるという決定でした。静的メソッドをC++プログラマにとって使い慣れた方法で機能させることは、実行するまで待つ必要がないため、非常に高速でした。

462
Nathan Hughes

個人的には、これは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がどのように統計を処理するのかに合わないので、これが「悪いデザイン」であると言うのであれば、私の返事は「まあ、当たり前だよ」です。最初の投稿で述べたように、うまくいきません。しかし、これがうまくいった言語、つまり仮想関数のように静的変数をオーバーライドすることができる言語には根本的に悪いことがあるという意味で悪い設計であると言うなら、これはどういうわけかあいまいさをもたらすか、不可能です。私は、「どうしてですか?このコンセプトの何が問題なのですか」と答えます。

私は私が与える例はやりたいことは非常に自然なことだと思います。どのインスタンスデータにも依存しない関数を持ち、インスタンスから独立して呼び出すことが非常に合理的であり、インスタンスメソッド内から呼び出すことができるようなクラスがあります。なぜこれはうまくいかないのでしょうか。私は何年にもわたってこの状況に何度も遭遇しました。実際には、関数を仮想にしてから、その呼び出しの中で唯一の目的がダミーインスタンスを使って仮想メソッドに渡す静的メソッドであることを目的とした静的メソッドを作成することでそれを回避します。それはそこに着くための非常にロータリーのような方法のようです。

171
Jay

簡単な答えは、それは完全に可能ですが、Javaはそれをしません。

Javaのcurrents state of affairsを示すコードを次に示します。

ファイル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.

ここで、onlyのケースは、驚くかもしれない(そして質問は)、最初にのように見えるケース:

「オブジェクトインスタンス(obj.staticMethod())で呼び出された場合でも、どの静的メソッドが呼び出されるかを決定するためにランタイム型は使用されません。」

そしてlastの場合:

「クラスのオブジェクトメソッド内から静的メソッドを呼び出すとき、選択される静的メソッドは、クラス自体からアクセス可能なものであり、クラスからnotですオブジェクトの実行時タイプを定義します。」

オブジェクトインスタンスで呼び出す

静的呼び出しはコンパイル時に解決されますが、非静的メソッド呼び出しは実行時に解決されます。静的メソッドはinherited(親から)ですが、overridden(子供による)。そうでなければ、これは驚くかもしれません。

オブジェクトメソッド内からの呼び出し

Objectメソッド呼び出しはランタイム型を使用して解決されますが、静的(class)メソッド呼び出しは、コンパイル時(宣言済み)型を使用して解決されます。

ルールを変更する

これらのルールを変更して、例の最後の呼び出しChild.printValue()と呼ばれるように、コンパイラは宣言されたクラスでコンパイル時に呼び出しを解決するのではなく、実行時に型を提供する必要があります。オブジェクト(またはコンテキスト)の。オブジェクトメソッドの呼び出しが今日のように、静的呼び出しは(動的)型階層を使用して呼び出しを解決できます。

これは簡単に実行でき(Java:-Oを変更した場合)、まったく不合理ではありませんが、いくつかの興味深い考慮事項があります。

主な考慮事項は、静的メソッド呼び出しでこれを行う必要があるwhichを決定する必要があることです。

現時点では、Javaには言語でこの「癖」があり、obj.staticMethod()呼び出しがObjectClass.staticMethod()呼び出しに置き換えられます(通常は警告付き)。 [注:ObjectClassobjのコンパイル時タイプです。]これらは、この方法でオーバーライドするのに適した候補です。 、objの実行時タイプを使用します。

これを行うと、メソッド本体が読みにくくなります。親クラスの静的呼び出しは、潜在的にdynamically "re-routed"になる可能性があります。これを回避するには、クラス名を使用して静的メソッドを呼び出す必要があります。これにより、コンパイル時の型階層により、呼び出しがより明確に解決されます(現在のように)。

静的メソッドを呼び出す他の方法は、より注意が必要です。this.staticMethod()は、thisの実行時型をとるobj.staticMethod()と同じ意味でなければなりません。ただし、これにより、装飾なしで(明らかにローカル)静的メソッドを呼び出す既存のプログラムで頭痛の種になる可能性があります(this.method()とほぼ同じです)。

では、装飾のない呼び出しstaticMethod()についてはどうでしょうか?今日と同じことを行い、ローカルクラスコンテキストを使用して何をすべきかを決定することをお勧めします。そうでなければ、大きな混乱が生じます。もちろん、method()は、methodが非静的メソッドである場合はthis.method()を意味し、methodが静的メソッドである場合はThisClass.method()を意味します。これもまた混乱の原因です。

その他の考慮事項

この動作を変更した場合(および静的呼び出しを潜在的に動的に非ローカルにした場合)、おそらくfinalの修飾子としてのprivateprotected、およびstaticの意味を再検討したいでしょう。 _クラスのメソッド。 private staticメソッドとpublic finalメソッドはオーバーライドされないため、コンパイル時に安全に解決でき、ローカル参照として読み取るのに「安全」であるという事実に全員が慣れる必要があります。

38
Steve Powell

実は私たちは間違っていました。
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

;)

22
Patlatus

静的メソッドはJVMによってグローバルとして扱われ、オブジェクトインスタンスにはまったく結び付けられていません。

(Smalltalkのような言語のように)クラスオブジェクトから静的メソッドを呼び出せれば概念的には可能かもしれませんが、Javaではそうではありません。

_編集_

overload staticメソッドを使うことができます、それで大丈夫です。しかし、クラスはファーストクラスのオブジェクトではないため、 オーバーライド 静的メソッドを使用することはできません。実行時にリフレクションを使用してオブジェクトのクラスを取得することはできますが、取得したオブジェクトはクラス階層と平行にはなりません。

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()を使用します。静的メソッドはオブジェクトにバインドされていないため、静的メソッドにはthissuperの概念はありません。静的メソッドはグローバル関数です。結果として、多態性の概念もなく、したがって、メソッドのオーバーライドは意味がありません。

しかし、SmalltalkのようにMyClassが実行時にメソッドを呼び出すオブジェクトであった場合(あるいは、1つのコメントからわかるようにJRubyかもしれませんが、JRubyについては何も知りません)、これは可能です。

そうそう…もう一つ。あなたはオブジェクトobj1.staticMethod()を通して静的メソッドを呼び出すことができますが、それは本当にMyClass.staticMethod()のためのシンタックスシュガーであり、避けるべきです。最近のIDEでは、通常、警告が発生します。なぜ彼らがこのショートカットを許可したのか私にはわかりません。

17
ewernli

メソッドのオーバーライドは、 dynamic dispatching によって可能になります。つまり、宣言されたオブジェクトの型によってその動作が決定されるのではなく、実行時の型が決定されます。

Animal lassie = new Dog();
lassie.speak(); // outputs "woof!"
Animal Kermit = new Frog();
Kermit.speak(); // outputs "ribbit!"

lassieKermitは両方ともAnimal型のオブジェクトとして宣言されていますが、動的ディスパッチはコンパイル時ではなく実行時に bind メソッド呼び出し.speak())を呼び出すだけなので、その動作(メソッド.speak())は異なります。

さて、ここでstaticキーワードが意味を成し始めるところです: Word "static"は "dynamic"の反対語です。 だから静的メソッドをオーバーライドできないのは、静的メンバに動的ディスパッチがないからです - 静的は文字通り「動的ではない」という意味です。 動的にディスパッチした(そしてオーバーライドされる可能性がある)場合、staticキーワードはもはや意味をなさないでしょう。

13

はい。実際にはJavaは静的メソッドをオーバーライドすることを可能にします、そしてもしあなたがJavaで静的メソッドをオーバーライドするならば理論的にいいえそしてそれはコンパイルと実行をスムーズにしますがコンパイルして実行することはできません。あなたはあなたの答えを得るでしょう。例えばクラスAnimalと静的メソッドeat()があり、そのサブクラスでその静的メソッドをオーバーライドすると、Dogと呼びます。その後、どこにいてもDogオブジェクトをAnimal Referenceに割り当て、Java Dogのeat()に従ってeat()を呼び出すべきでしたが、静的にオーバーライドするとAnimalsの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はLate Bindingを使用しているため、結果は異なっていました。つまり、メソッドは実行時にのみ呼び出され、静的メソッドの場合には呼び出されません。静的メソッドでは、コンパイラは実行時ではなくコンパイル時にメソッドを呼び出すので、オブジェクトに従ってではなく参照に従ってメソッドを取得します。じゃない。

8
Shubham Soni

Javaでオーバーライドされたメソッドがどのように振る舞うべきかという観点から考えると、答えはNOです。しかし、静的メソッドをオーバーライドしようとしても、コンパイラエラーは発生しません。つまり、オーバーライドしようとしても、Javaがそれをやめることはありません。しかし、あなたは確かにあなたが非静的メソッドの場合と同じ効果を得ることはありません。 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がオーバーライドされた場合、この行は3行目と同じであるはずです。実行時型のオブジェクトでstaticMethod()を呼び出すのは、SuperClassではなくSubClassです。これは、静的メソッドが常にコンパイル時の型情報のみを使用して解決されることを確認します。

5
Rupesh Yadav

Java(および多くのOOP言語ですが、私は全然話せません。そして一部は静的ではありません)すべてのメソッドは固定のシグニチャ(パラメータと型)を持ちます。仮想メソッドでは、最初のパラメータが暗黙的に指定されます。オブジェクト自体への参照、およびオブジェクト内から呼び出されると、コンパイラは自動的にthisを追加します。

静的メソッドに違いはありません - それらはまだ固定シグネチャを持っています。しかし、メソッドstaticを宣言することで、コンパイラはそのシグネチャの先頭に暗黙のオブジェクトパラメータを含めてはならないことを明示的に述べました。したがって、これを呼び出す他のコードは、 をスタック上のオブジェクトへの参照を配置しようとしてはいけません 。もしそうすると、スタック上のパラメータが1つずれた間違った場所にあるため、メソッドの実行は機能しません。

この2つの違いのために。仮想メソッドは常にコンテキストオブジェクトへの参照(つまりthis)を持っているので、そのオブジェクトのインスタンスに属するヒープ内のものを参照することが可能です。しかし静的メソッドでは、参照が渡されないため、コンテキストが不明なため、そのメソッドはオブジェクト変数やメソッドにアクセスできません。

静的または仮想のすべてのメソッドに対してオブジェクトコンテキストが渡されるようにJavaが定義を変更することを望むのであれば、本質的には仮想メソッドのみを持つことになります。

誰かがopにコメントを求めたように - この機能が欲しいというあなたの理由と目的は何ですか?

私はRubyをあまり知りません、これがOPによって言及されたように、私はいくつかの研究をしました。 Rubyでは、クラスは本当に特別な種類のオブジェクトであり、(動的な場合でも)新しいメソッドを作成できることがわかりました。クラスはRubyのフルクラスオブジェクトですが、Javaにはありません。これは、Java(またはC#)で作業するときに受け入れなければならないことです。 C#は何らかの形の動的言語を追加していますが、これらは動的言語ではありません。実際には、Rubyは私が見つけることができる限り「静的な」メソッドを持っていません - その場合これらはシングルトンクラスオブジェクトのメソッドです。その後、このシングルトンを新しいクラスでオーバーライドすることができます。前のクラスオブジェクトのメソッドは、新しいクラスで定義されているメソッドを呼び出します(正しい?)。そのため、元のクラスのコンテキストでメソッドを呼び出した場合でも、元の統計のみが実行されますが、派生クラスでメソッドを呼び出すと、親クラスまたはサブクラスからメソッドが呼び出されます。興味深いことに、それにはある程度の価値があります。それは異なる思考パターンを取ります。

あなたはJavaで働いているので、あなたは物事を行うその方法に適応する必要があるでしょう。なぜ彼らはこれをしたのですか?まあ、おそらく利用可能な技術と理解に基づいてその時点でパフォーマンスを向上させるためです。コンピュータ言語は絶えず進化しています。十分に戻って、OOPのようなものはありません。将来的には、他の新しいアイデアがあるでしょう。

_ edit _ :もう1つのコメント。私は違いを見てきましたし、私自身がJava/C#を開発しているので、あなたがRubyのような言語から来たのであれば、Java開発者から得た答えがなぜ混乱するのでしょうか。 JavaのstaticメソッドはRubyのclassメソッドと同じではありません。 Java開発者はこれを理解するのに苦労するでしょう、逆にRuby/Smalltalkのような言語で主に働く人々と同様に。 Javaも静的メソッドについての別の方法として「クラスメソッド」を使用していますが、これと同じ用語がRubyでは異なる意味で使用されていることからも、これがどのように非常に混乱するのかわかります。 JavaにはRubyスタイルのクラスメソッドがありません(申し訳ありません)。 Cに見られるように、Rubyは本当に古い手続き型関数であるJavaスタイルの静的メソッドを持っていません。

ところで - 質問をありがとう!私は今日クラスメソッド(Rubyスタイル)について何か新しいことを学びました。

5
Kevin Brock

オーバーライドすることで、オブジェクトの種類に応じて多態性を作り出すことができます。静的メソッドはオブジェクトとは関係ありません。そのため、Javaは静的メソッドのオーバーライドをサポートできません。

4
DeveloperArnab

一般に、静的メソッドを「オーバーライド」することを許可するのは意味がありません。実行時にどのメソッドを呼び出すべきかを判断するのに良い方法がないからです。 Employeeの例で、RegularEmployee.getBonusMultiplier()を呼び出した場合、どのメソッドが実行されることになっていますか?

Javaの場合、オブジェクトインスタンスを通して呼び出される限り、静的メソッドを「オーバーライド」することが可能な言語定義を想像することができます。ただし、これを実行するには、通常のクラスメソッドを再実装し、実際に利点を追加することなく言語に冗長性を追加するだけです。

4
Lars

私は好きで、Jayのコメントを二重にします( https://stackoverflow.com/a/2223803/1517187 )。
これはJavaの悪い設計であることに同意します。
他の多くの言語は、以前のコメントで見たように、静的メソッドのオーバーライドをサポートしています。私もJayが私と同じようにDelphiからJavaにやってきたと感じます。
Delphi(Object Pascal)は、OOPを実装した最初の言語です。
市販のGUI製品を書くのは過去の唯一の言語だったので、多くの人がその言語を使ったことがあることは明らかです。そして - はい、Delphiでは静的メソッドをオーバーライドできます。実際には、Delphiの静的メソッドは "クラスメソッド"と呼ばれていますが、Delphiは "Delphi静的メソッド"という異なる概念を持っていました。あなたがレイトバインディングを使用しなければならなかったメソッドをオーバーライドするには、 "virtual"ディレクティブを宣言します。それで、それはとても便利で直感的でした、そして、私はJavaでこれを期待するでしょう。

4
Patlatus

オーバーライドは、ポリモーフィック動作をサポートするためにインスタンスメンバー用に予約されています。静的クラスメンバは特定のインスタンスに属しません。代わりに、静的メンバーはクラスに属し、その結果、オーバーライドはサポートされません。これは、サブクラスが保護およびパブリックインスタンスメンバーのみを継承し、静的メンバーを継承しないためです。別のアプローチを評価するために、インタフェースおよびリサーチファクトリや戦略設計パターンを定義することをお勧めします。

4
Athens Holloway

Javaでオーバーライドするということは、単に、そのメソッドのコンパイル時の型ではなく、オブジェクトのランタイム型に基づいて特定のメソッドが呼び出されることを意味します(これは、オーバーライドされた静的メソッドの場合です)。静的メソッドはクラスメソッドであるためインスタンスメソッドではないので、どの参照がどのObjectまたはインスタンスを指しているかとは関係ありません。静的メソッドの性質上、それは特定のクラスに属しているからです。サブクラスで再宣言することはできますが、そのサブクラスは親クラスの静的メソッドについては何も知りません。これは、前述したように、それが宣言されているクラスだけに固有のものだからです。オブジェクト参照を使用してそれらにアクセスすることは、Javaの設計者によって与えられた単なる余分な自由であり、我々は確かに彼らがそれを制限したときだけその慣行をやめることを考えるべきではありません http://faisalbhagat.blogspot.com/2014/09 /method-overriding-and-method-hiding.html

2
faisalbhagat

オーバーライドすることで、動的多態性を実現します。静的メソッドをオーバーライドすると言うとき、あなたが使おうとしている言葉は矛盾しています。

静的な言う - コンパイル時、オーバーライドは動的多態性のために使用されます。両者は本質的に反対であり、したがって一緒に使用することはできません。

動的な多態性の振る舞いは、プログラマがオブジェクトを使用してインスタンスメソッドにアクセスしたときに発生します。 JREは、使用しているオブジェクトの種類に基づいて、さまざまなクラスのさまざまなインスタンスメソッドをマップします。

静的メソッドをオーバーライドすると言うときは、静的メソッドは、コンパイル時にリンクされるクラス名を使用してアクセスするので、実行時に静的メソッドとメソッドをリンクするという概念はありません。そのため、静的メソッドの「オーバーライド」という用語自体は意味がありません。

注:たとえあなたがオブジェクトでクラスメソッドにアクセスしたとしても、それでもJavaコンパイラはそれを見つけるのに十分知的であり、そして静的リンクをするでしょう。

2
user1923551

この質問への回答は簡単です。staticとマークされたメソッドまたは変数はクラスにのみ属します。したがって、静的メソッドはスーパークラスにのみ属するため、サブクラスで継承することはできません。

2
G4uKu3_Gaurav

静的メソッド、変数、ブロック、またはネストしたクラスオブジェクトではなくクラス全体に属する

Javaのメソッドは、オブジェクト/クラスの動作を公開するために使用されます。ここでは、メソッドがstatic(つまり、静的メソッドはクラスの振る舞いのみを表すために使われる)であるので)クラス全体の振る舞いを変更/オーバーライドすると、基本的な柱の一つの現象に違反するオブジェクト指向プログラミング、つまり高凝集度。(コンストラクタはJavaの特別な種類のメソッドであることを忘れないでください)

High Cohesion - 1つのクラスは1つの役割のみを持つ必要があります。たとえば、自動車クラスは自動車オブジェクトのみを生成し、自転車、トラック、飛行機などは生成しません。のみ。

したがって、Javaプログラミング言語を設計しながら。言語デザイナーは、メソッドを本質的に静的にすることによってのみ、開発者がクラスの振る舞いをそれ自体に保つことができると考えました。


以下のコードでは静的メソッドをオーバーライドしようとしていますが、not)でコンパイルエラーが発生することはありません。

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;
}}

これは、ここではメソッドをオーバーライドしているのではなく、単にre-declaringit)であるためです。Javaではメソッドの再宣言が可能です(静的/非静的)。

CarクラスのgetVehileNumber()メソッドからstaticキーワードを削除するとコンパイルエラーになりますので、change/ Vehicleクラスのみに属するstaticメソッドの機能)を試みています。

また、getVehileNumber()がfinal)として宣言されていると、コードはコンパイルされません。finalキーワードにより、プログラマはメソッドを再宣言できません。

public static final int getVehileNumber() {
return VIN;     }

全体的に見て、これは静的メソッドをどこで使用するかについてのソフトウェア設計者の責任です。私は個人的にはクラスのインスタンスを作成せずにいくつかのアクションを実行するために静的メソッドを使用することを好みます。次に、クラスの動作を外界から隠すことです。

1
Rohit Gaikwad

静的メソッドをオーバーライドすると、どのような効果がありますか。インスタンスを介して静的メソッドを呼び出すことはできません。

MyClass.static1()
MySubClass.static1()   // If you overrode, you have to call it through MySubClass anyway.

編集:言語設計の不幸な見落としを通して、あなたはcanインスタンスを通して静的メソッドを呼び出すようです。一般的に誰もそれをしません。私の悪い。

1
fastcodejava

これが簡単な説明です。静的メソッドはクラスに関連付けられ、インスタンスメソッドは特定のオブジェクトに関連付けられます。オーバーライドを使用すると、特定のオブジェクトに関連付けられているオーバーライドされたメソッドのさまざまな実装を呼び出すことができます。そのため、オブジェクトにも関連付けられていない静的メソッドをオーバーライドすることは直観的ではありませんが、そもそもクラス自体をオーバーライドすることになります。そのため、静的メソッドは、それを呼び出しているオブジェクトに基づいてオーバーライドすることはできません。常に静的メソッドは、それが作成されたクラスに関連付けられます。

1
Rafsan Mobasher

簡単な解決策:シングルトンインスタンスを使用してください。オーバーライドと継承を許可します。

私のシステムには、渡された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!";
  }

}
1