8

私はJavaで継承のコツをつかもうとしていますが、サブクラスのメソッドをオーバーライド(およびフィールドを非表示)する場合でも、「super」キーワードを使用してスーパークラスからアクセスできることを学びました。

私が知りたいのは、オーバーライドされていないメソッドに「super」キーワードを使用する必要があるかどうかです。

違いはありますか(オーバーライドされていないメソッド/非表示のフィールドの場合)?

以下に例をまとめました。

public class Vehicle {
    private int tyreCost;

    public Vehicle(int tyreCost) {
         this.tyreCost = tyreCost;
    }

    public int getTyreCost() {
        return tyreCost;
    }        
}

public class Car extends Vehicle {
    private int wheelCount;

    public Vehicle(int tyreCost, int wheelCount) {
        super(tyreCost);
        this.wheelCount = wheelCount;
    }   

    public int getTotalTyreReplacementCost() {
        return getTyreCost() * wheelCount;
    }   
}

具体的には、getTyreCost()オーバーライドされていない場合は、、または?をgetTotalTyreReplacementCost()使用する必要がありますgetTyreCost()super.getTyreCost()

スーパークラスのフィールドまたはメソッドにアクセスするすべてのインスタンスで(スーパークラスにアクセスしていることをコードで示すために)superを使用する必要があるのか​​、それともオーバーライド/非表示にする(目立つように)のみ使用するのか、疑問に思っています。

4

8 に答える 8

13

superオーバーライドされていない他のメソッドを参照するためにキーワードを使用しないでください。クラスを拡張しようとする他の開発者を混乱させます。

このようsuperにキーワードを使用するコードを見てみましょう。ここには 2 つのクラスがあります:DogCleverDog:

/* file Dog.java */
public static class Dog extends Animal {

    private String name;

    public Dog(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

}

/* file CleverDog.java */
public class CleverDog extends Dog {

    public CleverDog(String name) {
         super(name);
    }

    public void rollover() {
        System.out.println(super.getName()+" rolls over!");
    }

    public void speak() {
        System.out.println(super.getName() + " speaks!");
    }

}

ここで、あなたがプロジェクトの新しい開発者で、テレビに出ている賢い犬に特定の行動が必要であると想像してください。その犬はすべてのトリックを実行する必要がありますが、架空のテレビの名前で行く必要があります。これを実現するには、getName(...)メソッドをオーバーライドします...

/* file DogOnTv.java */
public class DogOnTv extends CleverDog {

    String fictionalName;

    public DogOnTv(String realName, String fictionalName) {
        super(realName);
        fictionalName = fictionalName;
    }

    public String getName() {
        return fictionalName;
    }

}

super...そして、元の開発者と彼らの異常なキーワードの使用によって設定された罠に陥ります!

上記のコードは機能しません。元のCleverDog実装では、キーワードgetName()を使用して呼び出されるためです。superつまりDog.getName()、オーバーライドとは関係なく、常に呼び出されます。したがって、新しいDogOnTvタイプを使用すると...

    System.out.println("Showcasing the Clever Dog!");
    CleverDog showDog = new CleverDog("TugBoat");
    showDog.rollover();
    showDog.speak();

    System.out.println("And now the Dog on TV!");
    DogOnTv dogOnTv = new DogOnTv("Pal", "Lassie");
    dogOnTv.rollover();

...間違った出力が得られます:

Showcasing the Clever Dog!
Tugboat rolls over!
Tugboat speaks!

And now the Dog on TV!
Pal rolls over!
Pal speaks!

superこれは、メソッドをオーバーライドするときに通常予想される動作ではないため、属さないキーワードを使用してこの種の混乱を引き起こすことは避ける必要があります。

ただし、これが実際に必要な動作である場合は、final代わりにキーワードを使用して、メソッドをオーバーライドできないことを明確に示します。

/* file CleverDog.java */
public class CleverDog extends Dog {

    public CleverDog(String name) {
         super(name);
    }

    public final String getName() { // final so it can't be overridden
        return super.getName();
    }

    public void rollover() {
        System.out.println(this.getName()+" rolls over!"); // no `super` keyword
    }

    public void speak() {
        System.out.println(this.getName() + " speaks!"); // no `super` keyword
    }

}
于 2012-10-09T16:11:46.397 に答える
3

superにアクセスするためのキーワードを使用しないことで、正しい方法を実行していgetTyreCostます。

ただし、メンバーを非公開に設定し、getter メソッドのみを使用する必要があります。

Usingsuperキーワードは、親メソッドを明示的に呼び出す必要があるコンストラクターおよびオーバーライドされたメソッド用に予約する必要があります。

于 2012-10-09T15:27:16.743 に答える
2

これは、コードの使用方法に依存します。指定super.getTyreCost()した後でそのメソッドをオーバーライドする場合。オーバーライドされたバージョンではなく、引き続きスーパークラスでメソッドを呼び出します。

私の意見では、super の呼び出しは後で混乱を招く可能性が高いため、明示的な必要がある場合にのみ指定するのが最適です。ただし、ここで提示したケースでは、動作に違いはありません。

于 2012-10-09T15:27:53.380 に答える
2

それはあなたのニーズとあなたの欲求に依存します。を使用superすると、コンパイル/アプリケーションは、現在のクラスの潜在的なメソッドを無視するように強制されます。親のメソッドのみを使用することを伝えたい場合は、使用superが適切です。また、クラスへの将来の変更が誤って親メソッドをオーバーライドすることを防ぎ、予想されるロジックを台無しにします。

ただし、これらのケースはかなりまれです。クラス内のどこでも super を使用すると、非常に混乱し、混乱したコードになります。ほとんどの一般的なケースでは、独自のクラス内でメソッドを呼び出すだけで、コンパイラ/jvm がどのメソッド (スーパーまたはローカル) を呼び出す必要があるかを判断できるようにする方が適切です。また、スーパーの戻り値をきれいにオーバーライド/変更/操作することもできます。

于 2012-10-09T15:30:37.103 に答える
1

を使用する場合はsuper、スーパー クラス メソッドを使用するように明示的に指示します (サブクラスがオーバーライドされたメソッドを持っているかどうかに関係なく)。それ以外の場合、最初に jvm はサブクラスのメソッド (オーバーライドされたメソッドがあれば) をチェックします。使用できない場合は、スーパー クラス メソッドを使用します。

于 2012-10-09T15:26:13.333 に答える
0

オーバーライドとは、同一のメソッド シグネチャを持つサブクラス内のスーパークラスからメソッドを再定義することを意味します。あなたの場合、getTyreCost()メソッドはオーバーライドされておらず、サブクラスでメソッドを再定義していないため、使用する必要はありsuper.getTyreCost()ませgetTyreCost()super.getTyreCost()superキーワードは、メソッドがオーバーライドされ、サブクラス内からのメソッド呼び出しをスーパークラスに実装する場合に使用されます。

于 2012-10-09T15:26:47.517 に答える
0

技術的には、この場合に呼び出されるのは継承されたバージョンであり、その実装は実際には親クラスによって提供されます。

superキーワードを使用しなければならないシナリオがあります。たとえば、Carそのメソッドをオーバーライドして、それ自体の別の実装を提供するが、親クラスによって提供される実装を呼び出す必要がある場合は、superキーワードを使用する必要があります。その場合、キーワードを省略することはできません。省略しsuperた場合、子クラス自体によって提供される実装を呼び出すことになるからです。

于 2012-10-09T15:32:21.787 に答える
-1

継承されたクラスをさらに変更しても、スーパー修飾子を追加する必要はなく、見逃した場合のエラーも防止することをお勧めします。

于 2012-10-09T15:25:43.177 に答える