2016-07-19 4 views
0

私はかなりJavaに慣れていて、オブジェクト指向の設計とプログラミングの基礎を練習しています。継承、オブジェクトの作成、およびsuper()呼び出しの正しい使用に関するいくつかの質問があります。スーパークラスのコンストラクタコールの使用はここで必要ですか?

次の点を考慮してください:

スーパー、

package pet 

public class Dog { 

    private String foodDogEats; 

    public Dog() { 
     this.foodDogEats; 
    } 

    public String getDogFood() { 
     return foodDogEats; 
    } 

    public void setDogFood() { 
     foodDogEats = "kibble"; 
    } 

} 

サブクラス、

package pet 

public class Fido extends Dog { 

    public Fido() { 
     super(); 
     Dog dog = New Dog(); 
     this.whatDoesFidoEat(); 
    } 

    public whatDoesFidoEat(Dog dog) { 
     System.out.println("Fido eats " + dog.getDogFood()); 
    } 

} 

とコントローラ。この例では

package pet 

public class MyDogFido { 

    public void MyDogFido() { 
     Fido fido = new Fido(); 
    } 

} 

オブジェクトは新しいFidoオブジェクトをインスタンス化し、そうすることの過程でwhatDoesFidoEat()で印刷動作を実行するために、です。私はいくつか質問がある - 私はすでに(Dogの延長である、と私は正しくリコール場合は、そのメソッドと変数を継承する)新しいFidoオブジェクトを呼び出しておりますので

を、Fido()コンストラクタで新しいDogオブジェクトのインスタンスであります冗長ですか?

super()の使用についてはどうですか?

DogオブジェクトをFido()にインスタンス化し、super()、またはその両方を呼び出すことは正しい動作ですか?

私は最初、制御クラスで両方を使用して同様のコードを書きました。この質問を書いた後、私の腸は私に電話するべきであることを私に伝えていますsuper()

私のサンプルコード(特にDog()コンストラクタのthis.foodDogEats;行もコメントしてください)もお気軽にご利用ください。

ありがとうございます!

+0

スーパークラスが 'private'データメンバを使用する場合、スーパークラスのget/setメソッドを使ってのみスーパークラスにアクセスできます。 'protected'を使うと、サブクラスが' this'を介してデータメンバーに直接アクセスできるようになります。スーパークラスの適切な機能に必要なget/setメソッドで何らかのロジックが発生する場合には、 'private'が使用されることがよくあります。 – RayfenWindspear

+0

これは正確には問題ではありませんが、 'Fido()'コンストラクタで行ったように、コンストラクタからfinalではないメソッドを呼び出さないようにしてください。 'Fido'をサブクラス化して' getDogFood() 'メソッドをオーバーロードすると、予期せぬ動作が発生する可能性があります。 – Sam

答えて

7

Dog dog = new Dog();行が冗長であることは間違いありません。 2番目の完全に別のオブジェクトDogが作成されます。

super()コールも不要です。別のスーパーコンストラクターを呼び出してその動作をオーバーライドしない限り、すべてのJavaコンストラクターは暗黙的にsuper()を呼び出します。

+0

説明をありがとう!だから基本的にどちらも - 私はFidoオブジェクトを作成するとき、それは私のためにすべてを行いますか?スーパークラス変数の設定はどうですか?スーパークラスセッターメソッドを呼び出す必要がありますか?スーパークラスのコンストラクタで呼び出すと、それをスキップできますか?もしそうなら、そうすることは容認できる慣行ですか? – drs

+0

スーパークラスにプライベート変数がある場合は、それ自身を設定する必要があります。サブクラスが構築時にこれらの値を設定したい場合は、スーパーコンストラクタに引数として渡すことができます。 – Sam

+0

スーパークラスのすべての変数をカプセル化の目的で非公開にする方が良いでしょうか? – drs

1

あなたのコードでは、スーパークラスにコンパイラエラーが表示されるはずです。あなたはそれがないと思うあなたは

this.foodDogEats; // should be a compiler error 

を持っているスーパークラスでは

は、あなたが持っているロジックを介して実行してみましょうか?単なる声明なので何もしません。 'this'キーワードは、作成したオブジェクトの特定のインスタンス内の変数を参照しているに過ぎず、何もしないことでエラーにつながります。

スーパークラスに引数のないコンストラクタがない場合を除き、スーパークラスはデフォルトで自動的に呼び出されるため、サブクラスでスーパークラスを呼び出す必要はありません。

+0

説明をありがとう!私は別のクラスでそのクラスの新しいオブジェクトを作成したときに 'this'を使用することについて心配する必要があり、その特定の変数を参照したいと思いますか? – drs

+0

継承を使用している場合、およびスーパークラスにも存在する(その名前が同じであることを意味する)そのクラスに変数、オブジェクトまたはメソッドがある場合にのみ、 'this'キーワードを使用する必要があります。 'this'キーワードは、実行時に、スーパークラスで定義されたインスタンスではなく、サブクラスで定義されたインスタンスを使用することを意味することを実行時に認識させます。それ以外の場合は、同じ名前が使用されたときに衝突が発生します。 – ucsunil

+0

この場合、サブクラスのコンストラクタで 'this'を使用する必要がありますか? – drs

1

super()の使用が正しいです。 Dogオブジェクトの使用は完全に不要です。

Dogを拡張すると、Fidoは非プライベートフィールドとメソッドを継承し、Dogとなります。そのため、あなたはFido簡素化することができます:

package pet; 

public class Fido extends Dog { 

    //Since this is a default constructor (no args and super() only), 
    //you don't even have to declare this. 
    public Fido() { 
     super(); 
    } 

    public void whatDoesFidoEat() { 
     System.out.println("Fido eats " + foodDogEats); 
    } 

} 

をそして、それの使用を簡素化:

package pet; 

public class MyDogFido { 

    public void MyDogFido() { 
     Fido fido = new Fido(); 
     //This is a setter method for your foodDogEats. It should be declared in Dog. 
     fido.setFoodDogEats("Beggin' Strips"); 
     fido.whatDoesFidoEat(); 
    } 

} 

あなたはまだあなたのFido()コンストラクタ呼び出しwhatDoesFidoEatを持つことができますが、オブジェクトの作成以降は思えませんメソッドに依存して、コンストラクタでそのような呼び出しを避けるほうが、より良い方法です。

編集:

あなたは建設時にfoodDogEatsを定義したい場合は、コンストラクタFido(String)定義することができます。

public Fido(String foodDogEats) { 
    this.foodDogEats = foodDogEats; 
} 

またはあなたのfoodDogEatsがクラスではなくに依存している場合をインスタンスと変わらない場合は、変数public static final FOOD_DOG_EATSを作成できます。 Fido.FOOD_DOG_EATSでアクセスすると、静的変数が継承されないため、Dog.FOOD_DOG_EATSと異なることに注意してください。

+0

ありがとうございました!だから一般的に、私はコンストラクタでsetterメソッドを呼び出す必要はないと思いますか? 'foodDogEats'変数が静的な値を持つことが事前に決められているこのような特定の用途ではどうでしょうか?それがあらかじめ決められていて変更されない場合は、コンストラクタの値を設定するのではなく、あらかじめクラスコードブロックの 'public static final'で値を設定するのではなく、setterを使うのはどうですか? – drs

+0

あなたは正しい軌道に乗っていますが、シナリオによっても異なります。私は編集で精緻化します。 – Zircon

+0

Hmm ..スーパークラスのコンストラクタにこの値を設定させるのが最善でしょうか?静的(読み込み:変更なし)の値を継承するサブクラスが必要な場合は、 – drs

1

コンストラクタがスーパークラスコンストラクタを明示的に呼び出さない場合、Javaコンパイラはスーパークラスの引数なしコンストラクタへの呼び出しを自動的に挿入します。スーパークラスに引数のないコンストラクタがない場合は、コンパイル時エラーが発生します。 Objectにはこのようなコンストラクタがあるため、Objectが唯一のスーパークラスであれば問題ありません。

2

私はすでに(Dogの延長である、と私は正しくリコール場合は、そのメソッドと変数を継承する)新しいFidoオブジェクトを呼び出しておりますので、Fido()コンストラクタ冗長に新しいDogオブジェクトをインスタンス化したものですか?

自体はですが、無意味で無駄です。新しいと異なるDogをインスタンス化し、それを無視します。ガベージコレクタは最終的にはそれをきれいにしますが、最初はそれを必要としませんでした。あなたのFidoは、クラスコンストラクタとメソッドの中でthis,のように参照できます。 a Dogです。そのようにするためにコンストラクタで何もする必要はありません。コンストラクタ内で何もできないようにすることはできません。

super()はどうなりますか?

クラスのコンストラクタを明示的に別の同じクラスのコンストラクタまたはスーパークラスのコンストラクタのいずれかを起動していない場合、それは暗黙的にsuper()を呼び出します。その場合、スーパークラスにそのような無限のコンストラクタがない場合、それはエラーです。 super()を明示的に呼び出すことは厳密には冗長ではありません。暗黙の呼び出しを抑制するためですが、そうする必要はありません。 super()を呼び出し、Fido()Dogオブジェクトをインスタンス化、またはその両方 - 正しい動作です

コンストラクタの1つを直接または間接的に呼び出すことによってスーパークラスを初期化します。その呼び出しは、スーパークラスがnullaryコンストラクターを持っていて、それが呼び出すものであれば暗黙的になることがあります。同様 -

(そこ使用状況についても不明な点が0​​コンストラクタで特にthis.foodDogEats;ライン)私のサンプルコードにコメントすること自由に感じなさい。

あなたが参照する行は誤りです。許可されていれば、デフォルト値のthis.foodDogEatsnull)と評価されます。他の効果はありません。それはかなり無意味です。

さらに、setDogFood()メソッドが奇妙です。不動産設定者は通常次の形式をとります:

public void setDogFood(String what) { 
     foodDogEats = what; 
    } 

あなたのオリジナルバージョンはちょっと無意味です。

+0

説明をありがとう! 'setDogFood()'に関して - 変数があらかじめ決められていて変更されていない場合、その変数の値を 'Dog()'コンストラクタで宣言する方が良いでしょうか? 'Dog'クラスコードブロックでそれを設定するのはどうですか?コードブロックに設定した場合、サブクラスアクセスを維持しながら適切にカプセル化するために、どのようにキーワードを設定する必要がありますか? – drs

+0

@ drsなら、あなたは 'Dog'の食べ物を変更する手段を提供するのを避けることができますが、それを真に変えずにサブクラスで変えることはできません。いずれにしても、提供したメソッドはコード内で呼び出されません。呼び出されない限り効果はありません。新しいインスタンスで 'null'と異なる値が必要な場合は、その値を設定するのはコンストラクタの仕事です。おそらく、適切な食物をパラメータとして受け入れるコンストラクタが必要です。 –

関連する問題