継承・実装の関係で悩んでいます

このQ&Aのポイント
  • アクセス制御を考えず、インスタンスかstaticかabstractの違いで継承する方法を検討しています。
  • クラスAからクラスBでオーバーライドしたメソッドは、クラスCでさらにオーバーライドできるのか疑問です。
  • 具体的なクラスの継承関係とインターフェースの実装関係を説明しています。
回答を見る
  • ベストアンサー

継承・実装の関係で悩んでいます。

継承・実装の関係について悩んでいます。 ここでは、アクセス制御を考えずに、インスタンスかstaticかabstract(ここではabstract final staticやabstract classのこと)の違いで、どう継承するのか考えています。 // 継承 はメソッドのオーバーライドのことを考えます。(オーバーロードは考えない) クラスAからクラスBでオーバーライドしたメソッドは、 クラスCでさらにオーバーライドできるのでしょうか? クラスCが クラスBのクラスAからオーバーライドしたメソッド をクラスBのメソッドとして見たときに、オーバーライドすることは可能なのでしょうか? クラスA │ インスタンスフィールドA │ staticフィールドA │ │ クラスA() { } │ │ インスタンスメソッドA () { } │ staticメソッドB() { } ↓ クラスB extends クラスA │ インスタンスフィールドA // 継承 │ インスタンスフィールドB │ staticフィールドB │ │ サブクラス1() { } // コンストラクタは継承しない、super()で呼び出す │ │ インスタンスメソッドA () { } // 継承 │ │ インスタンスメソッドB () { } │ staticメソッドB () { } ↓ クラスC extends クラスB implements インタフェースD, ... ↑ インスタンスフィールドA // クラスBのフィールドを継承 │ インスタンスフィールドB // クラスBのフィールドを継承 │ インスタンスフィールドC │ staticフィールドC │ │ サブクラス2() { } │ │ インスタンスメソッドA () { } // クラスBのメソッドを継承 │ インスタンスメソッドB () { } // クラスBのメソッドを継承 │ インスタンスメソッドD () { } // インタフェースDのメソッドを実装 │ インスタンスメソッドE () { } // インタフェースDのメソッドを実装 │ │ │ インスタンスメソッドC () { } │ staticメソッドC() { } │ interface インタフェースD extends インタフェースE ↑ │ staticフィールドD // public static final │ │ インスタンスメソッドD() { } // public abstract │ インスタンスメソッドE() { } // 継承 │ interface インタフェースE staticフィールドE // public static final インスタンスメソッドE() { } // public abstract

  • Java
  • 回答数6
  • ありがとう数6

質問者が選んだベストアンサー

  • ベストアンサー
  • x_jouet_x
  • ベストアンサー率68% (162/236)
回答No.6

this()とsuper()が同時に使えない件についてです。 this()もsuper()もコンストラクタ内の先頭で記述しなければならないという決まり事もありますが・・・。 また先ほどの回答で挙げたソースコードを元に説明しますね。では下記のソースコードをご覧下さい。 ---------- public class ClassA { protected String a; // インスタンス変数 protected int b; // インスタンス変数 // コンストラクタ1(引数: String, int) public ClassA(String a, int b) { this.a = a; this.b = b; } // コンストラクタ2(引数: String) public ClassA(String a) { this(a, 0); // this()の使用例1 } // コンストラクタ3(引数: int) public ClassA(int b) { this("", b); // this()の使用例2 } } ---------- 上記のソースコードの中で、コンストラクタ2とコンストラクタ3の中ではthis()メソッドを使っているため、super()は呼び出せません。 ではスーパークラスのコンストラクタはどうやって呼び出すのか? コンストラクタ2もコンストラクタ3もthis()メソッドを使って「コンストラクタ1を呼び出し」ているだけです。 ですから、コンストラクタ1にsuper()を追加すればいいのです。 // コンストラクタ1(引数: String, int) public ClassA(String a, int b) { super(); // スーパークラスのコンストラクタを呼び出す this.a = a; this.b = b; } このように記述すれば、コンストラクタ1、コンストラクタ2、コンストラクタ3のいずれもスーパクラスのコンストラクタは呼び出されることになります。 this()メソッドで別のコンストラクタを呼び出している ↓ どこかに実際の処理を行っているコンストラクタがある ↓ そのコンストラクタにsuper()を書く ということです。ちなみに引数なしのsuper()なのか、引数ありのsuper(...)なのかはスーパークラスのどのコンストラクタを呼び出したいかで変わりますが・・・。

pochi1234
質問者

お礼

this(a, 0) のように呼び出した先のコンストラクタで最後にsuper()を呼び出せば良いのですか(super()は書かなくても自動的に呼び出す) super()を呼び出すときは、参考書の例では引数なしバージョンしか書いていませんが、引数ありか、引数なしに気をつけなければいけませんね (引数なしコンストラクタのみthisを書けばいいと思っていましたが、よく考えたら、コンストラクタをオーバーロードして全部で3つあったら、最後だけsuper()のほうがいいですね) とても勉強になりました。 ありがとうございました。

その他の回答 (5)

  • x_jouet_x
  • ベストアンサー率68% (162/236)
回答No.5

まずthis()メソッドについてです。 下記のソースコードをご覧下さい。恐らくこういう使い方をイメージしていると思いますので・・・。 ---------- public class ClassA { protected String a; // インスタンス変数 protected int b; // インスタンス変数 // コンストラクタ1(引数: String, int) public ClassA(String a, int b) { this.a = a; this.b = b; } // コンストラクタ2(引数: String) public ClassA(String a) { this(a, 0); // this()の使用例1 } // コンストラクタ3(引数: int) public ClassA(int b) { this("", b); // this()の使用例2 } } ---------- 上記のソースコードの中でthis()メソッドを使用している箇所は2つありますが、1つ目のthis()メソッドを例にして説明しますね。 「this()の使用例1」とコメントがあるところで、this(a, 0); と記述していますが、これは引数に(String, int)を渡していますから実際には上記ソースコードのコンストラクタ1を呼び出していることになります。 この場合は変数の初期化だけですから、 public ClassA(String a) { this.a = a; this.b = 0; } と書いても同じことですが、コンストラクタ内での処理が長くなる場合はthis()メソッドを使った方がソースコードがすっきりします。 またthis()メソッドというのは、コンストラクタでの処理はほとんど同じでも引数の種類や数が異なるためコンストラクタが複数作られてしまう場合によく使われます。 例えば、 public ClassA(int a, int b, int c, String d, String e) { // 何らかの処理 } なんてコンストラクタがあったら、使う(newする)側も1つ1つ引数を書かなければならず面倒です。でももし、「特に指定がないなら、b=0, c=0, d=null, e=nullに設定していいよ」という決まり事が出来たら、使う側が毎回 ClassA clsA = new ClassA(1, 0, 0, null, null); と書かなくても済むようにClassA側で新たに public ClassA(int a) { this(a, 0, 0, null, null); } とコンストラクタを作成した方がいいですよね。

pochi1234
質問者

お礼

とてもわかりやすい説明ありがとうございます。 this() = メソッドなんですか? this()は、コンストラクタでの処理はほとんど同じでも引数の種類や数が異なるためコンストラクタが複数作られてしまう場合によく使われるとのことですが、 this() を使うことで、super()が使えなくなってしまいますが、 実際の開発では、this()を多用しても良いのでしょうか? ケースバイケースかもしれませんが。

  • x_jouet_x
  • ベストアンサー率68% (162/236)
回答No.4

回答#3の補足です。回答#3では分かりやすくするために、 ----- public ClassB() { super(); // ClassAのコンストラクタを呼び出す // その他の処理 } ----- と書きましたが、引数のないスーパークラスのコンストラクタは実際にはコンパイルするときにコンパイラが勝手に追加しちゃいます。ですので、上記のコードはsuper();を明示的に書かなくても結果は一緒なんですけどね・・・。 ClassAの引数のあるコンストラクタで ----- public ClassA(String hehehe) { foo = "hogehoge"; } ----- のように変数等の初期化処理を行っていれば、先の回答#3に書いたようにスーパークラスのコンストラクタを呼び出してやる必要があります。

pochi1234
質問者

補足

super()つけなくても、自動で追加するのは知ってるんです... this()は引数なしコンストラクタにのみ追加するものなのでしょうか?

  • x_jouet_x
  • ベストアンサー率68% (162/236)
回答No.3

> super()を自動で呼び出すということは、そのクラスのコンストラクタ内で上位クラスのインスタンスを作れる?ということなのでしょうか? super()は継承でコンストラクタをオーバーライドした場合、そのコンストラクタ内の先頭でしか使えませんよ。 例えば、ClassB extends ClassAを考えた場合、 public ClassB() { super(); // ClassAのコンストラクタを呼び出す // その他の処理 } こんな感じです。次に、 public class ClassA { protected String foo; // コンストラクタ public ClassA() { foo = "hogehoge"; // 変数fooの初期化 } } のようにClassAではインスタンス変数をコンストラクタの中で初期化している場合を考えてみましょう。 ClassB extends ClassAで継承したら、ClassBの中で何も宣言しなくても変数fooが使えるというところは理解できましたか? 例えば、ClassBの中で public void methodB() { System.out.println(foo); } のように、ClassBの中で宣言していない変数fooが使えます。これはClassAから変数とメソッドを引き継いでいるからです。 さて話を戻して、変数fooは「ClassAのコンストラクタの中」で初期化されています。ということはClassBの中で、初期化された変数fooを使用したければClassBの中でClassAのコンストラクタを呼ばないといけませんよね? そういった場合に、 public ClassB() { super(); // ClassAのコンストラクタを呼び出す // その他の処理 } とsuper()を使います。

pochi1234
質問者

お礼

super()については少し理解できました、this()の場合ですが、 例えとして、newで何も設定しなかったときに、this("NO NAME", 0); みたいな使い方をして、 次のコンストラクタに渡すと思うのですが。 やはりコンストラクタが3つ以上ある場合が多いと思います。 そうすると次のコンストラクタでもthis()を使ってしまうと、super()を呼び出せなくなってしまうので、そこが疑問です。 もしかして、引数2つあったとしたら、3つ目のコンストラクタに飛びますね(コンストラクタはオーバーロードしてるし) つまりthis()は、クラスの最初にある、引数なしのコンストラクタにのみ使ったほうがいいのでしょうか?

  • x_jouet_x
  • ベストアンサー率68% (162/236)
回答No.2

サブクラスのサブクラスなんてJavaのクラスではいくらでも出てますよ。 JavaのAPIリファレンスを参照することができるのであれば、java.util.LinkedHashSetクラスをご覧になって下さい。 様々なクラスを継承した上で多数のインタフェースを実装してますよ。 > クラスAを変更したときに、クラスCにどう影響がでるのか、 クラスA内で実装しているメソッドを変更しても、それをオーバーライドしているクラスCのメソッドには何も影響は出ませんよ。 ただし、オーバーライドする中で public void methodA() { super.methodA(); … } のようにスーパークラスのメソッドを呼び出している場合は別ですが・・・。 継承やオーバーライドについてはあまり難しく捉えずに理解するようにして下さい。 それから、疑問に感じたら一度ご自分でコードを書いて動作を確認してみるのも1つの手ですよ。

pochi1234
質問者

お礼

サンプルソースを作ってみたところオーバーライドの意味を理解できました。 private フィールドにすることで、インスタンスが変な動作をすることもありませんですし、必要なメソッドだけオーバーライドして、すでに作らているものは再利用できるということを理解しました。 ただコンストラクタのsuper()について、そのメリットが理解できなくて困っています。 this()を使えば、super()は呼び出されませんが。 super()を自動で呼び出すということは、そのクラスのコンストラクタ内で上位クラスのインスタンスを作れる?ということなのでしょうか? 意味不明な質問ですいません。

  • x_jouet_x
  • ベストアンサー率68% (162/236)
回答No.1

まず1点、「継承」というのはスーパークラスに実装された変数やメソッドを引き継ぐということです(privateは除きますが)。 例えば特に明示しない場合、全てのクラスのスーパークラスはObjectクラスになっているので、Objectクラスに実装されたfinalize()メソッドやgetClass()メソッドはサブクラスの中で実装していなくても使用できる仕組みになっています。 オーバーライドというのはその名の通り、スーパークラスから引き継いだメソッドをサブクラスの中で上書き(処理を変更)するということです。 例えば、上記に挙げたgetClass()メソッドはサブクラスの中でオーバーライドされていればそれが呼び出され、オーバーライドされていなければObjectクラスのgetClass()メソッドが呼び出されるだけです。 それを踏まえて、 >クラスAからクラスBでオーバーライドしたメソッドは、 >クラスCでさらにオーバーライドできるのでしょうか? もちろんできます。 クラスCでオーバーライドしていない場合でも、クラスC内でそのメソッドを呼び出すことも可能です。この場合、クラスBで実装した処理が行われます。 >クラスCが クラスBのクラスAからオーバーライドしたメソッド >をクラスBのメソッドとして見たときに、オーバーライドすることは可能なのでしょうか? この質問が今ひとつ分かりません(すみません)。

pochi1234
質問者

お礼

オーバーライドできるんですか、 クラスが2階層だと理解できるのですが、 3階層になると急に理解できなくなってしまいます。 クラスAを変更したときに、クラスCにどう影響がでるのか、 メソッドとコンストラクタについて、私はまだよく理解していないみたいです。汗

関連するQ&A

  • 継承、実装についてまとめています。この図は正しいですか?

    継承、実装についてまとめています。この図は正しいですか? クラス1 から継承した クラス2のものを、クラス3で継承するのでしょうか? クラス1 │ int a; │ static int b; │ │ クラス1() { } │ │ int methodA () { } │ static int methodB() { } ↓ サブクラス1 extends クラス1 │ int a; // 継承 │ int c; │ static int d; │ │ サブクラス1() { } // コンストラクタは継承しない、super()で呼び出す │ │ int methodA () { } // 継承 │ int methodC() { } │ static int methodD() { } ↓ サブクラス2 extends サブクラス1 implements サブインタフェース1, サブインタフェース2… ↑ int a; // サブクラス1のフィールドを継承 │ int c; // 継承 │ int e; │ static int f; │ public static final int g; // 実装(サブインタフェース1) │ public static final int h; // 実装 │ │ サブクラス2() { } │ │ int methodA () { } // サブクラス1のメソッドを継承 │ int methodC() { } // 継承 │ int methodE() { } │ static int methodF() { } │ int methodG() { } // 実装(サブインタフェース1) │ int methodH() { } // 実装 │ interface サブインタフェース1 extends スーパインタフェース1... ↑ public static final int h; │ │ public abstract int methodE() { } // 継承 │ public abstract int methodH() { } │ interface スーパーインタフェース public static final int g; public abstract int methodG() { }

    • ベストアンサー
    • Java
  • singletonによるインターフェイスの実装

    Java勉強中の初心者です。 標題の件についてお願いします。 以下、簡単に条件を説明させていただきます。 Aクラス = メインクラス Bクラス = インターフェイスクラス Cクラス = DとEを動的に生成するクラス Dクラス = インターフェイスを実装するクラス Eクラス = インターフェイスを実装するクラス AクラスにB.getInstance(name)があります。 for文の無限ループがあります。 Cクラス class C { public static B getInstance(String name) { // Aクラスのaと変数nameが比較して一致したら // Dクラスのインスタンス生成 // 一致しなかったらEクラスのインスタンス生成 if(A.a.equals(name)){ return D.getInstance(); }else{ return E.getInstance(); } } } Dクラス class D implements B{ private D() { } public static D getInstance() { D d = new D(); return d; } // インターフェイスでのメソッド省略します。 } Eクラス class E implements B{ private E() { } public static E getInstance() { E e = new E(); return e; } // インターフェイスでのメソッド省略します。 } この条件の時にnewするたびにインスタンスが 生成されてしまいます。 インスタンスの生成が一度だけしか 生成されないようにするには、C,D,Eクラスで どのように記述すればいいか悩んでいます。 (骨組みは書けましたが) クラスを簡単に省略してわかりづらいと 思いますがよろしくお願いします。

    • ベストアンサー
    • Java
  • 継承について

    みなさま、どうかお知恵を貸して下さい。 javaを勉強中で、本を読みながら試しに動かしています。 現在、実現したい動作が実現可能かどうかを調べているところです。 そのため、環境やバージョン等は決まっておりません。 むしろ、実現可能な環境やバージョンがあれば、教えてください。 実現したい機能ーーーーーーーーーーーー 親クラスAにメンバーとメソッドを定義します。 Aを継承する子クラスBを定義します。 プログラム中で、A、Bのインスタンスを生成します。 そして、A、Bを継承するCのインスタンスを生成したいのです。 Cのメンバーやメソッドは、Bと同様のものです。 この場合、BのクラスからCのようなインスタンスを作成することは、可能なのでしょうか? ・・・Cを定義していないので、おそらく不可能かと思います。 やはりこういった場合、Aを継承しているBを継承するCクラスを定義しておく必要があると考えています。 では、Cを継承するD,Dを継承するE・・・というように、いくつ必要になるかわからない場合、最大数分継承したクラスを用意すべきでしょうか。 なぜ、そうしたいかというと、組織図のようなものを作成したいのですが、組織図を構成する人数は、ユーザーの任意としたいのです。 継承したクラスを用いれば、そのまま組織図の体系を表現できる気がしました。 質問が大雑把になってしまい、申し訳ないのですが、お力を貸していただければ幸いです。

    • ベストアンサー
    • Java
  • 継承について

    下の質問の回答、間違ってませんか? -------------------------------------------- 親クラスのフィールドをメソッドを全て継承することになります。よって、サブクラス2は、サブクラス1とスーパークラスのメンバーを全て持つことになります。サブクラス2をインスタンス化すると、サブクラス1とスーパークラスが全てインスタンス化(コンピューターのメモリ上等に配置)されます。 ただ、可視性というものがあり、サブクラスから親クラスのメンバーを直接取り扱えない場合があります。privateや可視性修飾子無しの場合、サブクラスから直接取り扱えません。ただ、継承はされているので、インスタンスとしては存在します。例えば、 class スーパークラス{ private int abc; public int getAbc(){ return this.abc; } というクラスがあり、これを継承したサブクラスがあったとします。 サブクラスからは、privateなメンバー変数abcは直接取り扱うことができません。ただ、publicなgetAbcメソッドはサブクラスから取り扱えます。これで何が分かるかといいますと、privateなメンバーでもサブクラスに継承されるのです。単に可視性の問題で直接取り扱えないだけなのです。 また、オーバーライドされたメソッドがあったとしても、super.メソッド()で親のメソッドも呼べますので、これも継承されているのです。

  • 「インタフェースを実装してそれが持つ抽象メソッドをオーバーライドする」

    「インタフェースを実装してそれが持つ抽象メソッドをオーバーライドする」は正しい? はじめまして。Javaのインタフェースに関する質問です。 私はこれまで、インタフェースを使うときは、インタフェースを実装してクラスを宣言し、そのクラス、またはサブクラスでインタフェースがもつすべての抽象メソッドを定義する、と理解していました。 しかし、下の例をみてください。抽象メソッドの定義を、インタフェースの実装の以前で与えています。問題無くコンパイルでき、実行できます。実行結果も以下の通りです。 インタフェースの抽象メソッドへの定義の与え方やその実行のされ方は、メソッドのオーバーライドと同様と思っていましたので、下記のコードでは「クラスBが抽象クラスではありません」や、「インタフェースの抽象メソッドがオーバーライドされていません」などの文法エラーがでると思っていました。 そこで、質問です。 インタフェースが持つ抽象メソッドの定義を与える場所について、または、これに関する説明のあるページなど、何かご存知でしたら教えてください。 ★コード★ interface X{   void show(); } class A{   public void show(){     System.out.println("A");   } } class B extends A implements X{ } public class Main{   public static void main(String[] args){     X x=new B();     x.show();   } } ★実行結果★ >java Main A ★Java環境★ java 1.6.0_21 javac 1.6.0_16

    • ベストアンサー
    • Java
  • 継承(extends)について

    extendsについてわからないことがあります。 次の3つのクラスがあった時、 class スーパークラス { ... class サブクラス1 extends スーパークラス { ... class サブクラス2 extends サブクラス1 {... サブクラス2は、サブクラス1でスーパークラスから継承しているフィールドをメソッドを継承するのでしょうか?

    • ベストアンサー
    • Java
  • JAVAのコンストラクタ、継承の問題を回答頼む

    commonパッケージにHeroクラスを継承した、SuperHeroクラスを作成してください * ●HP, POWER, ENDURANCEはHeroと同じでそれぞれ、(25, 10, 7) * フィールド * item : Item * メソッド * attackメソッドをオーバーライドし、 * powerフィールドの値に加えて、itemフィールドのadditionalDamage分を加算した値を返す * itemフィールドのアクセサ */ public static void main(String[] args) { // TODO SuperHeroインスタンスとSlimeインスタンスを作成し、それぞれの名前に"勇者(装備あり)", "スライム"を設定してください // TODO Itemクラスのインスタンスを作成し、("こんぼう", 5)をコンストラクタの引数にしてください // TODO SuperHeroインスンタンスのitemフィールドに作成したitemインスタンスをセットしてください // TODO SuperHeroインスンタンスのattackメソッドを呼び出して、戻り値を出力してください // ※ 15と出力されれば正解

  • staticメソッドの継承

    お世話になります。 static メソッドの継承についてなのですが、 class Parent {  public static String name = "Parent";  public static getName() {   return name;  } } class Child extends Parent {  public static String name = "Child"; } だと、 Parent.getName(); Child.getName(); はともに Parent を返します。 ChildにてgetName()をオーバーライドすれば望む結果が得られるのですが、何かスマートでは無いような気がしてしまいます。 継承したstaticメソッドは親の元で実行され、そしてアクセスするstatic変数が親というのは何故なのでしょうか? 根本的な質問かもしれませんが、よろしくお願いいたします。

    • ベストアンサー
    • Java
  • 継承について

    継承についてです。 class A { int x; } class B extends A{ public int test(){ return 1; } public static void main(String[]args){ A a = new B; a.test(); } } としたとき a.test(); という記述はできないものなのでしょうか?a.textでコンパル時にエラーが出ます。aはBのインスタンスを指しているから、test()もつかえるんじゃないかなとおもったのですが・・・ public int test(){return 0;}というのをクラスAに記述すればエラーは起こりませんが、これはわかります。 ウェブを探したのですが、検索の仕方が悪かったのかこれに関する記事をさがせなかったので質問いたしました。

    • ベストアンサー
    • Java
  • interfaceを実装するとは?

    interfaceを実装するとはどういうことですか? abstractはクラスの継承で 学校 -abstract(拡張)― 教室 ―abstract(拡張)― 生徒 と機能を細分化するものとわかりました。 インターフェースってなんですか・・

専門家に質問してみよう