静的メソッドはJavaで継承されますか?


142

Khalid MughalによるJava™SCJP認定のプログラマガイドを読んでいまし

継承の章では、

メンバーの継承は、宣言されたアクセシビリティと密接に関連しています。スーパークラスメンバーがサブクラスの単純な名前でアクセスできる場合(スーパーのような追加の構文を使用せずに)、そのメンバーは継承されたと見なされます

また、静的メソッドは継承されないことにも言及しています。ただし、以下のコードは完全に問題ありません。

class A
{
    public static void display()
    {
        System.out.println("Inside static method of superclass");
    }
}

class B extends A
{
    public void show()
    {
        // This works - accessing display() by its simple name -
        // meaning it is inherited according to the book.
        display();
    }
}

display()クラスで直接使用するにはどうすればよいですBか?さらに、B.display()動作します。

本の説明はインスタンスメソッドにのみ適用されますか?


stackoverflow.com/questions/4716040/…には興味深い情報があります。
マット

それは私のコピー、第1版でそれが言っていることではありません。実際の見積もりを提示してください。
ローン侯爵、2015

回答:


178

アクセス可能なすべてのメソッドは、サブクラスによって継承されます。

Sun Java チュートリアルから

サブクラスは、そのサブクラスがどのパッケージに入っているかに関係なく、その親のすべてのパブリックメンバーと保護されたメンバーを継承します。サブクラスがその親と同じパッケージにある場合は、親のパッケージプライベートメンバーも継承します。継承されたメンバーをそのまま使用する、それらを置き換える、非表示にする、または新しいメンバーで補足することができます

継承された静的(クラス)メソッドと継承された非静的(インスタンス)メソッドの唯一の違いは、同じシグネチャを使用して新しい静的メソッドを作成すると、古い静的メソッドは非表示にされ、オーバーライドされないことです。

オーバーライドと非表示の違いに関するページから。

非表示と上書きの違いには、重要な意味があります。呼び出されるオーバーライドされたメソッドのバージョンは、サブクラスのバージョンです。呼び出される隠しメソッドのバージョンは、スーパークラスから呼び出されるか、サブクラスから呼び出されるかによって異なります。


継承は、サブクラスでそのメンバーをオーバーライドできるかどうかに関係していますか?
Algorithmist

それは継承の一部ですが、すべてではありません。継承の他の主要な部分は、コードの再利用とポリモーフィズムです。
yincrash 2012

再定義には、オーバーライドのようないくつかのルールがありますか?
サレンダータクラン2013年

2
@Algorithmist正確ではありません。サブクラスが階層の上位にあるものはすべて、クラスが継承したものです。ただし、継承される静的メソッドはオーバーライドできず、非表示にするだけです(同じシグネチャで「再宣言」)。したがって、静的メソッドをfinalとして宣言することもできますが、これは問題ではありません。呼び出される静的メソッドはコンパイル時に既知です。非最終インスタンスメソッドでは、オーバーライドされる可能性があるため、解決はランタイムに延期する必要があります。
マーティンアンダーソン

1
最後の段落は完全に損なわれています!!! 「呼び出されるオーバーライドされたメソッドのバージョンは、サブクラスのバージョンです」これは真ではありません:言ってみます:呼び出されるオーバーライドされたメソッドのバージョンは、ランタイムで、オブジェクトを作成したオブジェクトに関連するJVMによってのみ決定されます電話:)
mounaim 14

14

それが本が本当に言っていることであるならば、それは間違っています。[1]

Java言語仕様#8.4.8の状態:

8.4.8継承、オーバーライド、および非表示

クラスCは、直接のスーパークラスから、次のすべてが当てはまるスーパークラスのすべての具象メソッドm(静的およびインスタンスの両方)を継承します。

  • mはCの直接のスーパークラスのメンバーです。

  • mはpublic、protected、またはCと同じパッケージ内のパッケージアクセスで宣言されています。

  • Cで宣言されたメソッドには、mの署名のサブ署名(8.4.2)である署名はありません。

[1]それは私のコピー、第1版、2000年ではそのことを言っていません。


13

次のコードの違いを体験できます。これは、コードを少し変更したものです。

class A {
    public static void display() {
        System.out.println("Inside static method of superclass");
    }
}

class B extends A {
    public void show() {
        display();
    }

    public static void display() {
        System.out.println("Inside static method of this class");
    }
}

public class Test {
    public static void main(String[] args) {
        B b = new B();
        // prints: Inside static method of this class
        b.display();

        A a = new B();
        // prints: Inside static method of superclass
        a.display();
    }
}

これは、静的メソッドがクラスメソッドであるためです。

A.display()とB.display()はそれぞれのクラスのメソッドを呼び出します。


1
しようとしているようなインスタンスで静的メソッドを呼び出すと、Javaでは機能しません。
Lucas C. Feijo 2016

これがこのプログラムの説明です。Bのオブジェクトのインスタンス化と継承が機能することを期待することは、静的メンバーでは不可能です。Eclipse /任意のIDEで同じコードを使用するか、javacを使用してコンパイルして実行してください
Gaurav

2
@ LucasC.Feijoは実際に機能します。少なくとも私のIDE(Eclipse)では。警告が出ます。それは良いスタイルではないかもしれませんが...それは別の話です。
dingalapadum 2017

2
@ LucasC.Feijoがインスタンスで静的メソッドを呼び出すことはお勧めしません。ただし、クラス名で静的メソッドを呼び出すのと同じように機能します。
Ziyang Zhang

5

B.display()が機能するのは、静的宣言によってメソッド/メンバーがクラスに属し、特定のクラスインスタンス(オブジェクト)に属さないためです。詳細については、こちらをご覧ください

もう1つ注意すべき点は、静的メソッドをオーバーライドすることはできません。サブクラスで同じシグネチャを使用して静的メソッドを宣言することはできますが、その動作は予想とは異なる場合があります。これがおそらく継承と見なされない理由です。ここで問題のあるシナリオと説明を確認できます


3

Javaの静的メソッドは継承されますが、オーバーライドできません。同じメソッドをサブクラスで宣言すると、スーパークラスメソッドをオーバーライドする代わりに非表示にします。静的メソッドはポリモーフィックではありません。コンパイル時に、静的メソッドは静的にリンクされます。

例:

public class Writer {
    public static void write() {
        System.out.println("Writing");
    }
}

public class Author extends Writer {
    public static void write() {
        System.out.println("Writing book");
    }
}

public class Programmer extends Writer {

    public static void write() {
        System.out.println("Writing code");
    }

    public static void main(String[] args) {
        Writer w = new Programmer();
        w.write();

        Writer secondWriter = new Author();
        secondWriter.write();

        Writer thirdWriter = null;
        thirdWriter.write();

        Author firstAuthor = new Author();
        firstAuthor.write();
    }
}

次のものを取得します。

Writing
Writing
Writing
Writing book

2

静的メソッドはJavaで継承されますが、ポリモーフィズムには参加しません。静的メソッドをオーバーライドしようとすると、スーパークラスの静的メソッドをオーバーライドするのではなく、単に隠すだけです。


この回答に反対票を投じる理由がわかりません。少なくとも最初の部分は、くっきりとクリアです。2番目の部分は、あまり技術的に取り上げるべきではありません。それ以外の場合は問題ありません。明確にするために、オーバーライドメソッドでは、戻り値の型が(サブタイプに)変わる可能性がありますが、静的メソッドの場合はそうではありません。技術的には「オーバーライドしようとする」は静的メソッドには適用されないため、言えることはできないということだけです。
sharhp 2017

2

この概念は見た目ほど簡単ではありません。継承なしで静的メンバーにアクセスできます。これはHasA関係です。親クラスも拡張することで静的メンバーにアクセスできます。これは、ISA関係(継承)であることを意味するものではありません。実際、静的メンバーはクラスに属しており、静的メンバーはアクセス修飾子ではありません。アクセス修飾子が静的メンバーへのアクセスを許可している限り、他のクラスでそれらを使用できます。公開されている場合と同じように、同じパッケージ内およびパッケージ外からもアクセスできます。プライベートではどこでも使用できません。デフォルトでは、パッケージ内でのみ使用できます。しかし、保護されるためには、スーパークラスを拡張する必要があります。したがって、静的メソッドを他のクラスに取得することは、静的であることに依存しません。アクセス修飾子によって異なります。だから、私の意見では、静的メンバーは、アクセス修飾子が許可する場合にアクセスできます。それ以外の場合は、ハサリレーションと同じように使用できます。そして、関係は継承ではありません。ここでも、静的メソッドをオーバーライドすることはできません。他のメソッドを使用できてもオーバーライドできない場合は、HasA関係です。それらをオーバーライドできない場合は継承ではないので、ライターは100%正しかったです。


親クラスを拡張することである「です-」の関係。アクセスがプライベートの場合、クラス内から使用できます。'protected'には、派生クラスと現在のパッケージのクラスが含まれます。ここにエラーが多すぎます。
ローン侯爵

0

静的メソッドはサブクラスで継承されますが、ポリモーフィズムではありません。静的メソッドの実装を作成すると、親のクラスメソッドはオーバーライドされずに非表示になります。継承されていない場合、どうすればアクセスできないのclassname.staticMethodname();でしょうか?


0

すべてのパブリックメンバーと保護メンバーはどのクラスからも継承できますが、デフォルトまたはパッケージメンバーは、スーパークラスと同じパッケージ内のクラスからも継承できます。静的メンバーか非静的メンバーかは関係ありません。

しかし、静的メンバー関数が動的バインディングに参加しないことも事実です。その静的メソッドのシグネチャが親クラスと子クラスの両方で同じ場合、ポリモーフィズムではなくシャドウイングの概念が適用されます。


0

静的メソッドをオーバーライドできますが、ポリモーフィズムを使用しようとすると、それらはクラススコープに従って機能します(通常の予想とは異なります)。

public class A {

    public static void display(){
        System.out.println("in static method of A");
    }
}

public class B extends A {

    void show(){
        display();
    }

     public static void display(){
        System.out.println("in static method of B");
    }

}
public class Test {

    public static void main(String[] args){
        B obj =new B();
        obj.show();

        A a_obj=new B();
        a_obj.display();


    }


}

最初のケースでは、o / pは "Bの静的メソッド内"です。#オーバーライドが成功します。2番目のケースでは、o / pは "Aの静的メソッド内"です#静的メソッド-ポリモーフィズムを考慮しません


-1

サブクラスで同じシグネチャを持つ静的メソッドを宣言できますが、実行時のポリモーフィズムがないため、オーバーライドとは見なされません。クラスのすべての静的メンバーは、クラスのロード時にロードされるため、コンパイル時に決定されるためです時間(実行時にオーバーライド)したがって、答えは「いいえ」です。


2
なぜ人々がいつも反対票を投じるのか、なぜ反対票を投じるのかという理由を知らないのです。
surajs1n 2016

この答えはオーバーライドについてです。問題は継承についてです。
ローンの侯爵

-1

多くの人が答えを言葉で述べています。これはコードの拡張説明です:

public class A {
    public static void test() {
        System.out.println("A");
    }
    public static void test2() {
        System.out.println("Test");
    }
}

public class B extends A {
    public static void test() {
        System.out.println("B");
    }
}

// Called statically
A.test();
B.test();
System.out.println();

// Called statically, testing static inheritance
A.test2();
B.test2();
System.out.println();

// Called via instance object
A a = new A();
B b = new B();
a.test();
b.test();
System.out.println();

// Testing inheritance via instance call
a.test2();
b.test2();
System.out.println();

// Testing whether calling static method via instance object is dependent on compile or runtime type
((A) b).hi();
System.out.println();

// Testing whether null instance works
A nullObj = null;
nullObj.hi();

結果:

A
B

Test
Test

A
B

Test
Test

A

A

したがって、これが結論です。

  1. staticを。を介して静的に呼び出すと、そのクラスで定義されたstatic、または継承チェーン内でそれに最も近いクラスが検索されます。これは、静的メソッドが継承されていることを証明しています。
  2. インスタンスから静的メソッドが呼び出されると、コンパイル時の型で定義された静的メソッドが呼び出されます。
  3. 静的メソッドはnullインスタンスから呼び出すことができます。私の推測では、コンパイラーは変数タイプを使用してコンパイル中にクラスを見つけ、それを適切な静的メソッド呼び出しに変換します。

1
単なるコードは説明ではなく、デモンストレーションです。この質問への回答では、単に言及されていない実装の動作を示すだけでなく、規範的な参照を引用する必要があります。
ローン侯爵

-2

静的メンバーはユニバーサルメンバーです。どこからでもアクセスできます。


4
文字通りどこからでもアクセスできますが、これは誤りです:static!=スコープ。明確にしたいかもしれません:-)
kleopatra

実際、この答えは文字どおりに解釈すると問題ありません。コード内の1つの場所で、クラスの静的メンバーにアクセスできない場所を考えることはできません。静的スコープ、静的コンストラクター、インスタンスコンストラクター、メソッド、プロパティ、さまざまなクラス、任意のスコープでこれらにアクセスできます。クラスと静的メソッドがパブリックである限り、静的初期化子に循環依存がないことを前提として、どこからでもアクセスできます。本質的に、静的メンバーは継承されず、クラスレベル(つまり、ユニバーサル)のメソッドであり、どこからでもアクセスできます。
Triynko 2014

@Triynkoプライベートなメソッド、またはパッケージの外部からアクセスされるパッケージ保護されたメソッドの場合、答えは間違っています。
ローンの侯爵

@kleopatra-オフトピック。javaスイング?最近、人々は実際にそれを使用していますか?
MasterJoe2 2016年

@Pavanはクラスの外部からプライベートstaticを呼び出してみます。うまくいきません。
Rakesh Yadav 2017

-2

継承は非静的メンバーのみのため、静的メンバーはサブクラスに継承されません。静的メンバーはクラスローダーによって静的プール内にロードされます。継承は、オブジェクト内に読み込まれるメンバーのみに適用されます


完全に間違っています。JLS#8.4.8を参照してください。
ローン侯爵
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.