Javaのオーバーライドと非表示-混乱


88

オーバーライドとJavaでの非表示の違いについて混乱しています。これらの違いについて誰かが詳細を提供できますか?Javaチュートリアルを読みましたが、サンプルコードはまだ混乱していました。

より明確にするために、私はオーバーライドをよく理解しています。私の問題は、一方がインスタンスレベルにあり、もう一方がクラスレベルにあるという事実を除いて、非表示がどのように異なるかがわからないことです。

Javaチュートリアルコードを見る:

public class Animal {
    public static void testClassMethod() {
        System.out.println("Class" + " method in Animal.");
    }
    public void testInstanceMethod() {
        System.out.println("Instance " + " method in Animal.");
    }
}

次に、サブクラスがありCatます。

public class Cat extends Animal {
    public static void testClassMethod() {
        System.out.println("The class method" + " in Cat.");
    }
    public void testInstanceMethod() {
        System.out.println("The instance method" + " in Cat.");
    }

    public static void main(String[] args) {
        Cat myCat = new Cat();
        Animal myAnimal = myCat;
        Animal.testClassMethod();
        myAnimal.testInstanceMethod();
    }
}

それから彼らは言う:

このプログラムからの出力は次のとおりです。

動物のクラスメソッド。

Catのインスタンスメソッド。

私にとって、クラスtestClassMethod()から直接クラスメソッドを呼び出すと、クラス内のメソッドがAnimal実行されるという事実Animalは非常に明白であり、特別なことは何もありません。次にtestInstanceMethod()、を参照からに呼び出します。そのmyCatため、実行されたメソッドがCat。のインスタンスのメソッドであることは明らかです。

私が見たところ、通話の非表示はオーバーライドと同じように動作するのに、なぜその区別をするのでしょうか。上記のクラスを使用してこのコードを実行すると、次のようになります。

Cat.testClassMethod();

取得します: Catのクラスメソッド。 しかしtestClassMethod()、Catからを削除すると、次のようになります。Animal のclassメソッド。

これは、親と同じ署名を持つ静的メソッドをサブクラスに書き込むと、ほとんどオーバーライドされることを示しています。

うまくいけば、私は混乱している場所を明確にし、誰かが光を当てることができます。よろしくお願いします!


回答:


103

オーバーライドは基本的に遅延バインディングをサポートします。したがって、実行時にどのメソッドが呼び出されるかが決定されます。非静的メソッド用です。

非表示は他のすべてのメンバー(静的メソッド、インスタンスメンバー、静的メンバー)用です。これは、初期のバインディングに基づいています。より明確に言えば、呼び出されるか使用されるメソッドまたはメンバーは、コンパイル時に決定されます。

あなたの例では、最初の呼び出しAnimal.testClassMethod()staticメソッドの呼び出しであるため、どのメソッドが呼び出されるかはかなり確実です。

2番目の呼び出しでmyAnimal.testInstanceMethod()は、非静的メソッドを呼び出します。これは、実行時ポリモーフィズムと呼ばれるものです。どのメソッドを呼び出すかは、実行時まで決定されません。

詳細については、「オーバーライドと非表示」を参照してください


3
迅速な回答をありがとう、これはそれを明らかにします!JavaRanchの例では、クラスを直接使用するのではなく、変数を使用してクラスメソッドを呼び出しているため、理解しやすくなっていることに気付きました。Javaチュートリアルでは、インスタンスを使用して静的メソッドを呼び出すことはおそらく適切ではないため、クラスを直接使用したと思いますが、Animal.testClassMethod()の代わりにmyAnimal.testClassMethod()を使用する必要がありました
Lostlinkpr 2012年

例ではなく、適切に言葉でそれを置くことができるための+1!:)
WhyNotHugo 2012年

@風影我愛羅過負荷と非表示に違いはありますか?
gstackoverflow 2014年

1
もちろん答えには同意しますが、どうprivate methodsですか?overriddenサブクラスがそれらの存在を知らないので、それらはあり得ません。したがって、それらはhidden代わりであるかもしれません。
Paschalis 2014

素晴らしい答え!完全を期すためにcoderanchで例を追加するかもしれませんが:)
Shubham Mittal 2016

19

静的メソッドは非表示になり、非静的メソッドはオーバーライドされます。呼び出しが「something()」と「this.something()」で修飾されていない場合の違いは顕著です。

私は本当にそれを言葉に置くことができないようです、それでここに例があります:

public class Animal {

    public static void something() {
        System.out.println("animal.something");
    }

    public void eat() {
        System.out.println("animal.eat");
    }

    public Animal() {
        // This will always call Animal.something(), since it can't be overriden, because it is static.
        something();
        // This will call the eat() defined in overriding classes.
        eat();
    }

}


public class Dog extends Animal {

    public static void something() {
        // This method merely hides Animal.something(), making it uncallable, but does not override it, or alter calls to it in any way.
        System.out.println("dog.something");
    }

    public void eat() {
        // This method overrides eat(), and will affect calls to eat()
        System.out.println("dog.eat");
    }

    public Dog() {
        super();
    }

    public static void main(String[] args) {
        new Dog();
    }

}

出力:

animal.something
dog.eat

1
では、「dog husky = new dog();」と呼ぶとどうなるでしょうか。そして、husky.Animal();それはanimal.somethingまたはdog.somethingを印刷しますか?私はその推測** WRONGが言っていること**これは、常にAnimal.something()を呼び出します
amarnathハリッシュ

@amarnathharishできません.Animal()Animal()コンストラクターであることを忘れないでください。
Dude156

そして、疑問に思っている人のためのさらなる明確化として、something()inがAnimal() 常にAnimalを呼び出す理由はsomething()、静的メソッドの呼び出しが実行時ではなくコンパイル時に解決されるためです。これは、静的メソッド呼び出しAnimal()が常に暗黙的にを呼び出していることを意味しAnimal.something()ます。これについて考えると、これは非常に直感的です。静的メソッドの呼び出しの前className.staticMethodName()に、同じクラス内にない限り、クラス名(つまり)を付ける必要があります。
Dude156

13

これは、オーバーライドと非表示の違いです。

  1. 親クラスと子クラスの両方のメソッドがインスタンスメソッドである場合、オーバーライドと呼ばれます。
  2. 親クラスと子クラスの両方のメソッドが静的メソッドである場合、それは非表示と呼ばれます。
  3. 1つのメソッドは、親および子のインスタンスとして静的にすることはできません。逆もまた同様です。

ここに画像の説明を入力してください


3
OPが言ったチュートリアルから直接そのテーブルを切り取って貼り付けても、彼は理解できませんでした。
wolfcastle 2012年

この表は非常に明確です。例では、すべてのケースが考慮されているわけではありません。
tutak 2013

3

私があなたの質問を正しく理解していれば、答えは「あなたはすでにオーバーライドしています」です。

「これは、親と同じ名前の静的メソッドをサブクラスに書き込むと、ほとんどオーバーライドされることを示しています。」

スーパークラスのメソッドとまったく同じ名前のサブクラスにメソッドを作成すると、スーパークラスのメソッドがオーバーライドされます。メソッドをオーバーライドするために@Overrideアノテーションは必要ありません。ただし、コードが読みやすくなり、実際にメソッドをオーバーライドしていることをコンパイラーに確認させます(たとえば、サブクラスメソッドのスペルを間違えませんでした)。


1
この回答は、オーバーライド/非表示に関してインスタンスメソッドと静的メソッドの対応に失敗しています。
Paul Bellora 2012年

3

オーバーライドは、インスタンスメソッドでのみ発生します。参照変数のタイプがAnimalで、オブジェクトがCatの場合、インスタンスメソッドはCatから呼び出されます(これはオーバーライドされます)。同じacatオブジェクトに対して、Animalのクラスメソッドが使用されます。

public static void main(String[] args) {
    Animal acat = new Cat();
    acat.testInstanceMethod();
    acat.testClassMethod();

}

出力は次のとおりです。

The instance method in Cat.
Class method in Animal.

2
public class First {

    public void Overriding(int i) {  /* will be overridden in class Second */ }

    public static void Hiding(int i) {  /* will be hidden in class Second
                                           because it's static */ }
}


public class Second extends First {

    public void Overriding(int i) {  /* overridden here */  }

    public static void Hiding(int i) {  /* hides method in class First
                                           because it's static */ } 
}

記憶のルールは単純です。拡張クラスのメソッドは、静的をvoidに変更したり、voidを静的に変更したりすることはできません。コンパイルエラーの原因になります。

しかし、void Nameに変更された場合void Nameオーバーライドです。

そして、static Name変更された場合はstatic Name非表示になります。(メソッドの呼び出しに使用される参照のタイプに応じて、サブクラスの静的メソッドとスーパークラスの静的メソッドの両方を呼び出すことができます。)


1

このコードスニペットでは、「static」の代わりに「private」アクセス修飾子を使用して、非表示メソッドとオーバーライドメソッドの違いを示しています。

class Animal {
// Use 'static' or 'private' access modifiers to see how method hiding work.
private void testInstancePrivateMethod(String source) {
    System.out.println("\tAnimal: instance Private method calling from "+source);
}
public void testInstanceMethodUsingPrivateMethodInside() {
    System.out.println("\tAnimal: instance Public method with using of Private method.");
    testInstancePrivateMethod( Animal.class.getSimpleName() );
}

// Use default, 'protected' or 'public' access modifiers to see  how method overriding work.
protected void testInstanceProtectedMethod(String source) {
    System.out.println("\tAnimal: instance Protected method calling from "+source);
}
public void testInstanceMethodUsingProtectedMethodInside() {
    System.out.println("\tAnimal: instance Public method with using of Protected method.");
    testInstanceProtectedMethod( Animal.class.getSimpleName() );
  } 
}  


public class Cat extends Animal {
private void testInstancePrivateMethod(String source) {
    System.out.println("Cat: instance Private method calling from " + source );
}
public void testInstanceMethodUsingPrivateMethodInside() {
    System.out.println("Cat: instance Public method with using of Private method.");
    testInstancePrivateMethod( Cat.class.getSimpleName());
    System.out.println("Cat: and calling parent after:");
    super.testInstanceMethodUsingPrivateMethodInside();
}

protected void testInstanceProtectedMethod(String source) {
    System.out.println("Cat: instance Protected method calling from "+ source );
}
public void testInstanceMethodUsingProtectedMethodInside() {
    System.out.println("Cat: instance Public method with using of Protected method.");
    testInstanceProtectedMethod(Cat.class.getSimpleName());
    System.out.println("Cat: and calling parent after:");
    super.testInstanceMethodUsingProtectedMethodInside();
}

public static void main(String[] args) {
    Cat myCat = new Cat();
    System.out.println("----- Method hiding -------");
    myCat.testInstanceMethodUsingPrivateMethodInside();
    System.out.println("\n----- Method overriding -------");
    myCat.testInstanceMethodUsingProtectedMethodInside();
}
}

出力:

----- Method hiding -------
Cat: instance Public method with using of Private method.
Cat: instance Private method calling from Cat
Cat: and calling parent after:
   Animal: instance Public method with using of Private method.
   Animal: instance Private method calling from Animal

----- Method overriding -------
Cat: instance Public method with using of Protected method.
Cat: instance Protected method calling from Cat
Cat: and calling parent after:
   Animal: instance Public method with using of Protected method.
Cat: instance Protected method calling from Animal

なぜそれが賛成票を獲得しなかったのか疑問に思います。
amarnathharish18年

0

私の最近のJava研究に基づく

  • サブクラスがサブクラス内の同じ署名を持つ同じメソッドを持っている場合、メソッドのオーバーライド
  • メソッドの隠ぺい、サブクラスは、同じメソッド名が、異なるパラメータを持っている場合。この場合、親メソッドをオーバーライドするのではなく、非表示にします。

OCP Java 7の本、70〜71ページの例:

public class Point {
  private int xPos, yPos;
  public Point(int x, int y) {
        xPos = x;
        yPos = y;
  }

  public boolean equals(Point other){
  .... sexy code here ...... 
  }

  public static void main(String []args) {
   Point p1 = new Point(10, 20);
   Point p2 = new Point(50, 100);
   Point p3 = new Point(10, 20);
   System.out.println("p1 equals p2 is " + p1.equals(p2));
   System.out.println("p1 equals p3 is " + p1.equals(p3));
   //point's class equals method get invoked
  }
}

しかし、次のメインを書くと:

  public static void main(String []args) {
   Object p1 = new Point(10, 20);
   Object p2 = new Point(50, 100);
   Object p3 = new Point(10, 20);
   System.out.println("p1 equals p2 is " + p1.equals(p2));
   System.out.println("p1 equals p3 is " + p1.equals(p3));
   //Object's class equals method get invoked
  }

2番目のメインでは、静的型としてObjectクラスを使用しているため、Pointオブジェクトでequalメソッドを呼び出すと、Pointクラスがパラメーターとして到着するのを待機していますが、Objectが到着します。したがって、equals(Object o)が存在するため、Objectクラスは実行されるメソッドと等しくなります。この場合、Pointのクラスequalsはオーバーライドされませんが、Objectクラスのequalsメソッドを非表示にします


0
public class Parent {

  public static void show(){
    System.out.println("Parent");
  }
}

public class Child extends Parent{

  public static void show(){
    System.out.println("Child");
  }
}

public class Main {

public static void main(String[] args) {
    Parent parent=new Child();
    parent.show(); // it will call parent show method
  }
}

// We can call static method by reference ( as shown above) or by using class name (Parent.show())

0

リンクされたJavaチュートリアルページでは、オーバーライドと非表示の概念について説明しています。

同じシグニチャ(名前に加えて、そのパラメータの数と型)を持つサブクラスのインスタンスメソッドと、スーパークラスのインスタンスメソッドとしての戻り値の型は、スーパークラスのメソッドをオーバーライドします。

サブクラスがスーパークラスの静的メソッドと同じシグネチャを持つ静的メソッドを定義している場合、サブクラスのメソッドはスーパークラスのメソッドを非表示にします。

静的メソッドを非表示にすることとインスタンスメソッドをオーバーライドすることの違いには、重要な意味があります。

  1. 呼び出されるオーバーライドされたインスタンスメソッドのバージョンは、サブクラスのバージョンです。
  2. 呼び出される非表示の静的メソッドのバージョンは、スーパークラスから呼び出されるかサブクラスから呼び出されるかによって異なります。

あなたの例に戻ります:

Animal myAnimal = myCat;

 /* invokes static method on Animal, expected. */
 Animal.testClassMethod(); 

 /* invokes child class instance method (non-static - it's overriding) */
 myAnimal.testInstanceMethod();

上記のステートメントはまだ非表示を示していません。

次に、以下のようにコードを変更して、異なる出力を取得します。

  Animal myAnimal = myCat;
  
  /* Even though myAnimal is Cat, Animal class method is invoked instead of Cat method*/
  myAnimal.testClassMethod();
  
  /* invokes child class instance method (non-static - it's overriding) */
  myAnimal.testInstanceMethod();

隠しているという言葉の意味を理解しようとしています。何が何を隠しているのですか?親クラスの静的メソッドは、(予想外に)呼び出されるために非表示になっていますか?または、Childクラスの静的メソッドは呼び出されないため、非表示になっていますか?
サソリ

0

上記の例に加えて、非表示とオーバーライドの違いを明確にするための小さなサンプルコードを次に示します。

public class Parent {

    // to be hidden (static)
    public static String toBeHidden() {
        return "Parent";
    }

    // to be overridden (non-static)
    public String toBeOverridden() {
        return "Parent";
    }

    public void printParent() {
        System.out.println("to be hidden: " + toBeHidden());
        System.out.println("to be overridden: " + toBeOverridden());
    }
}

public class Child extends Parent {

    public static String toBeHidden() {
        return "Child";
    }

    public String toBeOverridden() {
        return "Child";
    }

    public void printChild() {
        System.out.println("to be hidden: " + toBeHidden());
        System.out.println("to be overridden: " + toBeOverridden());
    }
}

public class Main {

    public static void main(String[] args) {
        Child child = new Child();
        child.printParent();
        child.printChild();
    }
}

child.printParent()出力の呼び出し:
非表示にする:
をオーバーライドする:子

child.printChild()出力の呼び出し:
非表示にする:
上書きされる:子供

上記の出力(特に太字でマークされた出力)からわかるように、メソッドの非表示はオーバーライドとは異なる動作をします。

Javaでは、メソッドに対してのみ非表示とオーバーライドの両方が許可されています。同じルールは変数には適用されません。変数のオーバーライドは許可されていないため、変数を非表示にすることしかできません(静的変数と非静的変数の違いはありません)。以下の例は、メソッドgetName()がオーバーライドされ、変数nameが非表示になる方法を示しています。

public class Main {

    public static void main(String[] args) {
        Parent p = new Child();
        System.out.println(p.name); // prints Parent (since hiding)
        System.out.println(p.getName()); // prints Child (since overriding)
    }
}

class Parent {
    String name = "Parent";

    String getName() {
        return name;
    }
}

class Child extends Parent {
    String name = "Child";

    String getName() {
        return name;
    }
}

0

実行時に、オーバーライドされたメソッドの子バージョンは、メソッド呼び出しが親クラスメソッドで定義されているか子クラスメソッドで定義されているかに関係なく、常にインスタンスに対して実行されます。このように、構文ParentClassName.method()を使用して親メソッドへの明示的な呼び出しが参照されない限り、親メソッドが使用されることはありません。または、メソッドの呼び出しが親クラスで定義されている場合、実行時に非表示メソッドの親バージョンが常に実行されます。


0

メソッドのオーバーライドでは、メソッドの解決はランタイムオブジェクトに基づいてJVMによって行われます。一方、メソッドの非表示では、メソッドの解決は参照に基づいてコンパイラーによって行われます。したがって、

コードが次のように記述されている場合、

public static void main(String[] args) {
        Animal myCat = new Cat();        
        myCat.testClassMethod();        
    }

出力は次のようになります
。AnimalのClassメソッド。


0

サブクラスに同じ静的メソッドがある場合、コンパイラがスーパークラスメソッドの実装を非表示にするため、非表示と呼ばれます。

コンパイラには、オーバーライドされたメソッドの可視性が制限されておらず、どちらを使用するかが決定されるのは実行時のみです。


0

これは、オーバーライドと非表示の違いです。

動物a = new Cat();

a.testClassMethod()は、メソッドの非表示の例であるため、親クラスのメソッドを呼び出します。呼び出されるメソッドは、参照変数のタイプによって決定され、コンパイル時に決定されます。

a.testInstanceMethod()は、メソッドのオーバーライドの例であるため、子クラスのメソッドを呼び出します。呼び出されるメソッドは、実行時にメソッドを呼び出すために使用されるオブジェクトによって決定されます。


-1

Javaで静的メソッドの非表示はどのように発生しますか?猫のクラスは動物のクラスを拡張しています。したがって、Catクラスには両方の静的メソッド(つまり、子クラスの静的メソッドと親クラスの静的メソッド)がありますが、JVMが親静的メソッドをどのように非表示にするのでしょうか。ヒープとスタックをどのように扱っていますか?


これは答えではありません。それは尋ねられた質問の延長です。それ自体が別の質問であるか、質問に対するコメントの一部である可能性があります。
Sri99 1119年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.