javaについて教えてください。


質問)
abstractを付与したクラスAがあると仮定します。
クラスAから、クラスBを継承させます。

クライアント側で、オブジェクトを生成する際に
クラスA 変数名 = new クラスB();
「変数として宣言しているクラスA」と「オブジェクト生成している(メモリ確保)クラスB」
と記述可能なメリットと理由がよくわかりません。

クラスA(absract)がオブジェクト生成できないため、
あえてクラスBを生成するってことなのでしょうか?
上の例だと、クラスBのメソッドは呼び出すことはできない筈なので。

サブクラスのアドレスを基底クラスの変数に格納しても問題ないってこと?
これは、基底クラスの領域しかアドレスを読み込めないってことなのでしょうか?

回答の条件
  • URL必須
  • 1人2回まで
  • 登録:
  • 終了:2009/09/26 08:08:00
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:tetsuyasodo No.3

回答回数11ベストアンサー獲得回数2

ポイント50pt

質問者様の疑問は、オブジェクト指向プログラミングをする上でよくある疑問だと思います。

すべてに言及すると本一冊以上のボリュームになってしまいますので

ここではヒントになりそうなコメントをさせていただきます。

なお、「オブジェクト脳のつくり方」という本が、このテーマをわかりやすく説明していると思います。

また、以下の説明ではabstractクラスのほかにinterfaceも説明に使いますが意味は同じです。

(それ自体で実体化できない・継承した実装クラスを使うなど)

まず「サブクラスのアドレスを基底クラスの変数に格納しても問題ないか?」ですが、

問題ないと考えてください。

「基底クラスの領域しかアドレスを読み込めない」ことになりますが、それで構いません。

なぜなら、基底クラスで定義しているメソッド/APIしか使わないために、あえてそうしているからです。

クライアントのコードでは

 クラスA 変数名 = new クラスB();  ・・・(1)

とした後、変数名に対して、いろいろなメソッドを呼び出す使い方をするでしょうが、

これ以降ではクラスBのことは意識しないようにしています。

あくまでクラスAのメソッド/APIのみを使ってコーディングをするようにします。

「なぜ機能が多いクラスBでなく機能が制限されたクラスAを使うのか?」というのが次に感じる疑問だと思います。

それは、

・クラスBの機能をすべてクライアントに見せることはしたくない → 「隠蔽」

・クラスAを継承した別の実装クラスCを使いたくなったときに、上記(1)以降のクライアントコードをいじる必要がない → 「ポリモーフィズム」

というメリットがあるためです。

オブジェクト指向の入門本などを読むと、よく自動車や動物などの例を出して上記隠蔽やポリモーフィズムを説明していますが

他に具体例を知りたい場合は、Java言語自体のListインターフェースやその実装クラスであるArrayList,Vector,LinkedListクラスなどを勉強すると頭に入りやすいかもしれません。

http://www.atmarkit.co.jp/fjava/javatips/136java026.html

id:masa193

ご回答ありがとうございます。

>「基底クラスの領域しかアドレスを読み込めない」ことになりますが、それで構いません。

>なぜなら、基底クラスで定義しているメソッド/APIしか使わないために、あえてそうしているからです。

少し納得できました。基本は、クラスAのメソッド/APIのみアクセス可能だが、abstractを修飾したメソッドは、

クラスBのメソッドを参照するようなしかけを施しているですね。

>・クラスAを継承した別の実装クラスCを使いたくなったときに、上記(1)以降のクライアントコードをいじる必要がない → 「ポリモーフィズム」

確かに、クラスのとっかえが効きそうですね。

2009/09/25 04:37:54

その他の回答4件)

id:goog20090901 No.1

回答回数637ベストアンサー獲得回数17

ポイント20pt

クラスA 変数名あ = new クラスB();

クラスA 変数名い = new クラスC();

変数名あと変数名いは、同様のクラスの型として扱えるので便利です。

クラスAというのは「型名」で、生成するのはnew で書いたクラスです。

>クラスA(absract)がオブジェクト生成できないため、

>あえてクラスBを生成するってことなのでしょうか?

間違ってます。

>サブクラスのアドレスを基底クラスの変数に格納しても問題ないってこと?

はい

>これは、基底クラスの領域しかアドレスを読み込めないってことなのでしょうか?

間違っています。

http://q.hatena.ne.jp/answer

id:decoy2004 No.2

回答回数20ベストアンサー獲得回数2

ポイント20pt

サンプルで説明します。

○1. 前提

javax.swing.AbstractButton => abstract class

JButton => javax.swing.AbstractButton を継承した class

JMenuItem => javax.swing.AbstractButton を継承した class

JToggleButton => javax.swing.AbstractButton を継承した class

○2. 《AbstractButton型を使わない場合》

boolean configured; //何か適当な条件。
JButton[] jbuttonList;
JMenuItem[] jmenuItemList;
JToggleButton[] jtoggleButtonList;

void setEnabledIfConfigured(JButton button) {
	if(configured) {
		button.setEnabled(true);
		jbuttonList[0] = button;
	}
}

void setEnabledIfConfigured(JMenuItem button) {
	if(configured) {
		button.setEnabled(true);
		jmenuItemList[0] = button;
	}
}

void setEnabledIfConfigured(JToggleButton button) {
	if(configured) {
		button.setEnabled(true);
		jtoggleButtonList[0] = button;
	}
}

○3. 《AbstractButton型を使う場合》

boolean configured; //何か適当な条件。
AbstractButton[] buttonList;

void setEnabledIfConfigured(AbstractButton button) {
	if(configured) {
		button.setEnabled(true);
		buttonList[0] = button;
	}
}

○4. 解説

《AbstractButton型を使わない場合》では concrete class 1個毎に別々に定義が必要です。

《AbstractButton型を使う場合》では concrete class が何個あっても1個だけの定義で十分です。

「abstract class がオブジェクト生成できないから」ではなく、

「concrete class オブジェクトを abstract class 型として扱いたいから」、

abstract class 型の変数に代入するのです。

Java プログラムではオブジェクトがどのアドレスに格納されているかは扱いません。

○参考情報

Java 入門 | 多態性(ポリモーフィズム) - http://msugai.fc2web.com/java/polymorphism.html

id:tetsuyasodo No.3

回答回数11ベストアンサー獲得回数2ここでベストアンサー

ポイント50pt

質問者様の疑問は、オブジェクト指向プログラミングをする上でよくある疑問だと思います。

すべてに言及すると本一冊以上のボリュームになってしまいますので

ここではヒントになりそうなコメントをさせていただきます。

なお、「オブジェクト脳のつくり方」という本が、このテーマをわかりやすく説明していると思います。

また、以下の説明ではabstractクラスのほかにinterfaceも説明に使いますが意味は同じです。

(それ自体で実体化できない・継承した実装クラスを使うなど)

まず「サブクラスのアドレスを基底クラスの変数に格納しても問題ないか?」ですが、

問題ないと考えてください。

「基底クラスの領域しかアドレスを読み込めない」ことになりますが、それで構いません。

なぜなら、基底クラスで定義しているメソッド/APIしか使わないために、あえてそうしているからです。

クライアントのコードでは

 クラスA 変数名 = new クラスB();  ・・・(1)

とした後、変数名に対して、いろいろなメソッドを呼び出す使い方をするでしょうが、

これ以降ではクラスBのことは意識しないようにしています。

あくまでクラスAのメソッド/APIのみを使ってコーディングをするようにします。

「なぜ機能が多いクラスBでなく機能が制限されたクラスAを使うのか?」というのが次に感じる疑問だと思います。

それは、

・クラスBの機能をすべてクライアントに見せることはしたくない → 「隠蔽」

・クラスAを継承した別の実装クラスCを使いたくなったときに、上記(1)以降のクライアントコードをいじる必要がない → 「ポリモーフィズム」

というメリットがあるためです。

オブジェクト指向の入門本などを読むと、よく自動車や動物などの例を出して上記隠蔽やポリモーフィズムを説明していますが

他に具体例を知りたい場合は、Java言語自体のListインターフェースやその実装クラスであるArrayList,Vector,LinkedListクラスなどを勉強すると頭に入りやすいかもしれません。

http://www.atmarkit.co.jp/fjava/javatips/136java026.html

id:masa193

ご回答ありがとうございます。

>「基底クラスの領域しかアドレスを読み込めない」ことになりますが、それで構いません。

>なぜなら、基底クラスで定義しているメソッド/APIしか使わないために、あえてそうしているからです。

少し納得できました。基本は、クラスAのメソッド/APIのみアクセス可能だが、abstractを修飾したメソッドは、

クラスBのメソッドを参照するようなしかけを施しているですね。

>・クラスAを継承した別の実装クラスCを使いたくなったときに、上記(1)以降のクライアントコードをいじる必要がない → 「ポリモーフィズム」

確かに、クラスのとっかえが効きそうですね。

2009/09/25 04:37:54
id:t-wata No.4

回答回数82ベストアンサー獲得回数13

ポイント30pt

URLはダミーです

http://q.hatena.ne.jp/

> 上の例だと、クラスBのメソッドは呼び出すことはできない筈なので。

これがメリットです。つまり、クラスBのコンストラクタを呼び出す行を除けば、このプログラムはクラスAにしか依存していないため、

クラスAを継承した別のクラスCを別途作った場合、このクラスCを使うように変更することが容易になります。

例えば、実行時に

ClassA aClass;

if (someCondition){

aClass = new ClassB();

} else {

aClass = new ClassC();

}

のように状況に応じ、実装クラスを変えることもできます。

このように、実装ではなく、インターフェイスにのみ依存させることで、プログラムの柔軟性を高め再利用しやすくなります。

もちろんそれができるように、抽象クラスやインターフェイスを設計することが重要ですが。

id:b-wind No.5

回答回数3344ベストアンサー獲得回数440

ポイント20pt

デザインパターン (ソフトウェア) - Wikipedia

おそらくその問いに関するこたえは「デザインパターン」を学習すると効率よく理解できると思います。


サルでもわかる 逆引きデザインパターン 第1章 はじめてのデザインパターン デザインパターンとは

主に「振る舞いに関するパターン」各種に利用されていますので、一読しておくことをお勧めします。


増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門

  • 作者: 結城 浩
  • 出版社/メーカー: ソフトバンククリエイティブ
  • メディア: 単行本

  • id:masa193
    分解すると
    クラスA 変数名;・・・①
    これは、クラスAがメモリ上に割り当てられて状態?(実領域は割り当てられていない)
    C言語だと、ポインタ変数を定義した状態だと思います。 int *p;

    変数名 = new クラスB();
    これは、クラスBのメモリを確保し(オブジェクト生成)、そのアドレスを変数名に確保している?

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません