こんばんは。
Javaプログラマを勉強しています。
サンプルプログラムで、オブジェクトの作成時、左辺と右辺でクラス名が異なる場合、
その一文ではどういうことが行われているのかイメージができません。
そこから原点に戻って、オブジェクトを作成する時の構文の一語一語の意味が分からなくなっています。
テキストによくある簡単な例だと、
-----------------
A a = new A();
-----------------
という構文があります。
この場合は左辺のAと右辺のAが同じであるため、このような構文が普通だと思い、ずっと理解した気になっていました。
ところが、
-----------------
class A {
…
}
class B extends A{
…
}
public class Main(){
public static void main(String[] args){
A a = new B();
…
}
-----------------
という構文が出てきた時、
A a = new B();
で、左辺のAと右辺のBは違っても大丈夫なの?何故違うの?どういう場合にこのような構文を使うの?
などの疑問が出てきて、
そもそもインスタンス化の構文
A a = new A();
のそれぞれは何を意味しているのか判らなくなり、
どこからどうやって理解していけば良いのか途方にくれています。
aはインスタンス化したオブジェクトの変数名であることは理解しています。
左辺のAと、右辺のAとnew演算子をどう理解すれば良いのか悩んでいます。
自分も何が分からないかを上手く説明できないのですが、
よろしくお願いします。
A 回答 (7件)
- 最新から表示
- 回答順に表示
No.7
- 回答日時:
No.5 お礼に対してです。
>「クラスを継承してクラスを作るのは良くない、
>インターフェイスできちんとメソッドを定義してあげて、
>インターフェイスを実装したクラスを作るだけにするのが良い」
これは言いたいことは理解できますが、かなり極端な意見です。
継承万能論の時代から、継承は正しく使わないと弊害があることが
知られるようになったとき、クリーンで多重継承が可能な
インターフェースがもてはやされた時期もありました。
今は使い方が熟してきていて、継承もインターフェースも
適材適所の時代です。
なにがなんでもインターフェースを実装するだけでは
共通の実装を利用できないのであまり現実的ではないですし、
それでは実装できない設計も数多くありますので
広く学習されることをお薦めします。
最後に、おすすめ書籍を3冊
1) バートランド・メイヤーの「Object Oriented Software Construction(邦訳は オブジェクト指向入門)」
オブジェクト志向全般の解説書。オブジェクト志向という考え方に大きな影響を与えた名著です。
但しはっきりいって入門書ではありません。ちょっと敷居が高いです。
2) Design Patterns Explained(邦訳 オブジェクト志向のこころ)
今回の質問のレベルの方の入門によいかも。
3) Effective Java
Java に特化した部分はこいつかな。
それでは頑張ってください。
追加の回答ありがとうございました。
お礼が遅くなり、すみません。
> 継承万能論の時代から、継承は正しく使わないと弊害があることが
> 知られるようになったとき、クリーンで多重継承が可能な
> インターフェースがもてはやされた時期もありました。
同僚の方にはJavaの世界で上の歴史があったことについて教えてもらいました。
> 今は使い方が熟してきていて、継承もインターフェースも
> 適材適所の時代です。
なるほど、そうなんですね。
同僚の方から「オブジェクト指向を突き詰めると、case文もif文も要らなくなる」なんて、
先のレベルの話もされましたが、自分にはまだ理解が及ばないので、まずは現在の理解レベルの足場固めをしたいと思います。
> 最後に、おすすめ書籍を3冊
ありがとうございます。本の推薦はありがたいです。
「オブジェクト指向のこころ」を購入しました。
同僚の方が「重箱の隅を突くようなJavaプログラマの勉強より、デザインパターンを覚えた方が良いんじゃないかな」とつぶやいていたので、ちょうど良い本のような気がします。
「Effective Java」については↓のページを見て、気に留めていました。
http://d.hatena.ne.jp/shuji_w6e/20110306/1299427 …
順に、読んで知識をつけていきたいと思います。
No.6
- 回答日時:
>No.1のお礼でも書きましたが、
>「スーパークラス型の変数に、
>サブクラス型のオブジェクトを代入できる」
>という点が理解しきれていません。(ANo.3のお礼)
念のために,Animal obj1 も Cow obj2 も参照型の変数だ,というJavaの基本の理解は大丈夫でしたっけ。
int i = 2011;
double d = (double)i;
のような基本型の変数における型変換は,int型とdouble型それぞれバイト数も内部形式も異なる変数における型変換ですが,
上記の obj1 と obj2 はともにバイト数も内部形式も同じ,参照型の変数(ポインタ)です。
new Animal() や new Cow() で生成されるオブジェクトはそれぞれ,内部に有するフィールドもメソッドも異なるでしょうし,総バイト数も異なるでしょう。でも,オブジェクトを指し示すJavaのポインタ変数はすべて同バイト数・同内部形式です。
ですから,
--------
>サブクラス型の変数をスーパークラス型の変数に
>キャストできるのは、
>「そういうルールだからだ」という理解レベルです。
>この点についても理解しきれていません。(ANo.1へのお礼)
その理解で別に間違っていないと思います。
オブジェクトを指すポインタ変数はすべて同バイト数・同内部形式ですから,原理的には「あらゆるクラス型の変数は,自分を含み他のどんなクラス型の変数にも自由に代入できる」はずです。
ただ,そのようなスパゲティプログラムを生み出すような混乱を招きたくないから,矛盾が起きない限りにおいて代入を認めるという「そういうルール」をJavaは科すことにしたのでしょう。
スーパークラス/サブクラスの関係があるなら,サブクラスはスーパークラスの性質を継承しています。であるならサブクラスの変数をスーパークラスの変数として扱うことに矛盾はありません。
--------
>・Animal obj = new Cow();
>・Animal obj = new Animal();
>・Cow obj = new Cow();
>の場合、全て異なる出力になるので、湧いた疑問ですが…。
>等価な構文ではないので、
>厳密には同じ動きはしないと思います。
>意識して使い分ける場面はあるのでしょうか?
Animalのインスタンスメソッドで定義してCowにオーバライドを許したいのか,
Animalのクラスメソッドで定義してCowにオーバライドさせたくないのか,
Animalの抽象メソッド(abstract)で定義してCowでの実装を指示したいだけなのか,
プログラマがそれを意識しているなら当然,使い分ける場面が存在します。
--------
>配列の話については、ピンときたものがありました。
ANo.3の回答と同じく私も,下位クラスのさまざまなオブジェクト群を,上位クラスの配列でまとめて扱い,同一のメッセージに対して異なるオブジェクトからそれぞれ異なる実行結果を得るポリモーフィズムの例が分かりやすいと思います。
図形クラスの場合でしたら,円・三角形・長方形に対して getArea()「面積を求めよ」メソッドを呼び出してみてはいかがですか。
class Q7175470 {
public static void main(String[] args) {
Cat neko = new Cat();
Pig buta = new Pig();
Cow ushi = new Cow();
Animal[] animals = new Animal[3];
animals[0] = neko;
animals[1] = buta;
animals[2] = ushi;
for (int i = 0; i < animals.length; i++) {
animals[i].cry();
}
}
}
abstract class Animal {
abstract void cry();
}
class Cat extends Animal {
void cry() {
System.out.println("meow");
}
}
class Cow extends Animal {
void cry() {
System.out.println("moo");
}
}
class Pig extends Animal {
void cry() {
System.out.println("oink");
}
}
追加の回答ありがとうございます。
お礼遅くなりまして、すみません。
> Animal obj1 も Cow obj2 も参照型の変数だ
> obj1 と obj2 はともにバイト数も内部形式も同じ,参照型の変数(ポインタ)
> オブジェクトを指し示すJavaのポインタ変数はすべて同バイト数・同内部形式です。
なるほど、この辺りの認識が曖昧でした。
現在、初めてC言語を教えてもらい、ポインタの知識も加わり、仰っている意味がよく分かるようになりました。
> オブジェクトを指すポインタ変数はすべて同バイト数・同内部形式ですから,原理的には「あらゆるクラス型の変数は,自分を含み他のどんなクラス型の変数にも自由に代入できる」はずです。
> 矛盾が起きない限りにおいて代入を認めるという「そういうルール」をJavaは科すことにしたのでしょう。
こちらの文章にも、目から鱗でした。
すとん、と腑に落ちました。
No.5
- 回答日時:
NO.3 への補足です。
ではもう少し難しい話をしてみます。
図形 図形1 = new 三角形();
という書き方だと 図形 のメソッドは呼び出せますが
三角形で追加したメソッドは呼び出せません。
図形で定義するメソッドをうまくえらんで、
例えば、SaveToStream() とか draw() とか move() とか、
全ての図形で共通のメソッドをうまくよういしてやれば、
大部分の処理は、図形型でかけるはずです。
ということは、図形の種類が増えても
基本的には処理に影響が及びません。
このような書き方をすることを
OCP(Open Close Principle)
といいます。
この原則はオブジェクトの種類の追加に対して
プログラムの修正をとても小さくする効果があります。
そして、OCPするために型をグループ化(抽象化)する作業を
CVA(共通性-可変性 分析)
などと言ったりします。
これらは各種書籍で詳説されていますの、調べてみてください。
Javaはこうした考え方に忠実に作られた言語ですが、
知らなければ宝の持ち腐れでしょう。
知らなくてもプログラムは作れますが、あとのメンテナンスで、
特に機能拡張の手間がまるで違ってきます。
追加の回答ありがとうございました。
同僚の人に、
「クラスを継承してクラスを作るのは良くない、
インターフェイスできちんとメソッドを定義してあげて、インターフェイスを実装したクラスを作るだけにするのが良い」
という話をしてもらいました。
「現実はそんな風に綺麗に出来上がらないけど」
とも言っておりました。
2000年に大学の授業で初めてJavaに触れましたが、当時はごまかされたような説明しか受けることができず、
11年経っても、まだこのようなレベルでいることに憤りを感じています。
書籍を読んでも簡単なものはきちんと説明されておらず、
難しいものは読んでも理解がついていかず、
その中間の書籍に出会うことが中々できません。
その中で自分は、Javaアソシエイツ → Javaプログラマと資格試験の勉強をすることで、
自分が判らずにいる所を判るようになろう、としているのですが、
中々スムーズに階段を登ることができずにいます。
Javaやオブジェクト指向を理解するには、
どう順序立てて学んでいけば良いのか、シラバスができれば良いなと思います。
No.4
- 回答日時:
A a = new A();
というのは,
A a;
a = new A();
という2行を1行にまとめて書いたもの。
多くの入門書に倣って,クラスA を「動物」クラスとして説明するなら,次のようになります。
A a;
動物オブジェクトを参照するための変数 a を作った。
でもまだ動物オブジェクトの実体は何も指し示していない。
a = new A();
動物クラスを実体化して,aがそれを指し示すようにした。
----------------
class B extends A {....}
A a = new B();
多くの入門書に倣って,クラスA を「動物」クラス,クラスB を「イヌ」クラスとして説明するなら,次のようになります。
class イヌ extends 動物 {....}
イヌは動物の一種である,イヌは動物の性質を継承している,したがって,
動物 a = new イヌ();
動物オブジェクトを参照するための変数 a が,
動物の一種である「イヌ」オブジェクトも指し示すことができるわけです。
回答ありがとうございました。
> 動物 a = new イヌ();
> 動物オブジェクトを参照するための変数 a が,
> 動物の一種である「イヌ」オブジェクトも指し示すことができるわけです。
やはり、この部分がどうしても腑に落ちません。
下記のサイトを見つけたのですが、こちらを読めば何となく分かりそうな気がしたので、一度このサイトをきちんと読んでみたいと思います。
http://www.kab-studio.biz/Programing/OOPinJava/0 …
No.3
- 回答日時:
これは継承という機能です。
ちょっと初等的な説明をしてみます。
例えば class 図形 があって
class 三角形 extends 図形
class 円 extends 図形
class 長方形 extends 図形
としておけば
図形 図形1 = new 三角形();
図形 図形2 = 図形1;
とできます。つまり様々な種類の図形を
図形型の変数に代入できるのです。
これって 便利だと思いませんか?
例えばたくさんの図形を処理するプログラムで、図形を配列で
持ちたい時、図形の種類別でしか配列を作れなかったら
悲しいですよね。
このようにグループを代表するクラスを考え出すことを抽象化、
グループを代表するクラスから、個々のクラスを定義することを
継承といいます。
とっかかりととして、簡単に説明してみましたが、
いかがでしょうか? 詳しくは「継承」 で調べてみてください。
この回答への補足
追加で疑問がわきました。
図形 図形1 = new 三角形();
と
三角形 図形1 = new 三角形();
は似たような振る舞いをすると思いますが、
等価な構文ではないので、
厳密には同じ動きはしないと思います。
意識して使い分ける場面はあるのでしょうか?
テキストで、
-----------
public class Sample5_6{
public static void main(String[] args){
Animal obj = new Cow();
System.out.println(obj.a);
System.out.println(obj.b);
obj.methodA();
obj.methodB();
}
}
class Animal{
int a = 10;
static int b = 50;
public void methodA(){
System.out.println("Animal : methodA()");
}
public static void methodB(){
System.out.println("Animal : methodB()");
}
}
class Cow extends Animal{
int a = 100;
static int b = 500;
public void methodA(){
System.out.println("Cow : methodA()");
}
public static void methodB(){
System.out.println("Cow : methodB()");
}
}
-----------
というサンプルがあり、
3行目が、
・Animal obj = new Cow();
・Animal obj = new Animal();
・Cow obj = new Cow();
の場合、全て異なる出力になるので、湧いた疑問ですが…。
同僚の人に「業務じゃ、こんなの使わない。いじわる問題だ」と言われましたが…。
回答ありがとうございます。
配列の話については、ピンときたものがありました。
図形[ ] 配列図形 = new 図形[3];
図形 図形1 = new 三角形();
図形 図形2 = new 円();
図形 図形3 = new 長方形();
配列図形[0] = 図形1;
配列図形[1] = 図形2;
配列図形[2] = 図形3;
という風にすれば、三角形・円・長方形クラスのオブジェクトを、
図形クラスの配列にまとめることができるということでしょうか。
確かに、
三角形 図形1 = new 三角形();
円 図形2 = new 円();
長方形 図形3 = new 長方形();
では、まとめにくそうなイメージです。
同僚の人に同様の質問を投げかけた時に、
「オブジェクト指向の考え方からすれば、
A a = new B();
と書く方が適切だ」
という言葉が何となく判った気がしました。
(同僚の人と話をしていた時は、"interface A"で話をしていましたが)
No.1のお礼でも書きましたが、
「スーパークラス型の変数に、サブクラス型のオブジェクトを代入できる」
という点が理解しきれていません。
No.1
- 回答日時:
A a = new A();
このイコールは、等式のイコールでは無く、右辺の処理結果を左辺に代入するという、代入のイコールです。
加えて言えば、Aの形をした変数aに、処理結果(Bの形をしている)を代入する式になります。
A a = new B();
こちらは、基本的に使わない、と考えておいた方が良いと思います。
# どうしても必要な場合は、一旦Aの形にCASTしてから(変えてから)代入することになります。
早速の回答ありがとうございます。
> このイコールは、等式のイコールでは無く、右辺の処理結果を左辺に代入するという、代入のイコールです。
これについての認識は問題ありません。
> 加えて言えば、Aの形をした変数aに、処理結果(Bの形をしている)を代入する式になります。
これについては、
「Aクラス型で変数aのオブジェクトがある」という所までは、認識は合っていると思います。
「そのオブジェクトはAクラス型だが、中身はBクラスのオブジェクト」ということなのでしょうか?
表現が難しいですが…。
この辺りの理解が曖昧です。
> # どうしても必要な場合は、一旦Aの形にCASTしてから(変えてから)代入することになります。
B b = new b();
A a;
a = (A)b;
ということでしょうか?
サブクラス型の変数をスーパークラス型の変数にキャストできるのは、
「そういうルールだからだ」という理解レベルです。
この点についても理解しきれていません。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Java JavaのSingletonパターンのprivateの持つ意味が分かりません。 5 2022/06/12 10:38
- Java java final 1 2022/06/10 22:49
- Java java 入力 3 4 3 出力 ABC DEFG HIJ このようなプログラムの書き方を教えてくだ 2 2022/07/15 14:18
- Java java 引数 戻り値のあるメソッド 3 2023/02/12 06:23
- 高校 方程式の証明 5 2022/05/12 09:29
- Java Java プログラム public class Main { public static void 3 2023/08/10 23:46
- Ruby 【JAVA】数字をひし形に出力するプログラムについて 2 2022/07/11 23:32
- 英語 提示した結果構文が非文となる理由について 1 2022/07/25 12:22
- Java 直し方について教えて頂きたいです。 4 2022/08/13 02:11
- PHP PHPの構文で間違えが分からない 5 2022/07/11 16:38
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・「みんな教えて! 選手権!!」開催のお知らせ
- ・漫画をレンタルでお得に読める!
- ・「これいらなくない?」という慣習、教えてください
- ・今から楽しみな予定はありますか?
- ・AIツールの活用方法を教えて
- ・【選手権お題その3】この画像で一言【大喜利】
- ・【お題】逆襲の桃太郎
- ・自分独自の健康法はある?
- ・最強の防寒、あったか術を教えてください!
- ・【大喜利】【投稿~1/9】 忍者がやってるYouTubeが炎上してしまった理由
- ・歳とったな〜〜と思ったことは?
- ・ちょっと先の未来クイズ第6問
- ・モテ期を経験した方いらっしゃいますか?
- ・好きな人を振り向かせるためにしたこと
- ・【選手権お題その2】この漫画の2コマ目を考えてください
- ・【選手権お題その1】これってもしかして自分だけかもしれないな…と思うあるあるを教えてください
- ・スマホに会話を聞かれているな!?と思ったことありますか?
- ・それもChatGPT!?と驚いた使用方法を教えてください
- ・見学に行くとしたら【天国】と【地獄】どっち?
- ・これまでで一番「情けなかったとき」はいつですか?
- ・この人頭いいなと思ったエピソード
- ・あなたの「必」の書き順を教えてください
- ・14歳の自分に衝撃の事実を告げてください
- ・人生最悪の忘れ物
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Class.forName("org.postgresql...
-
ゲッターを使わないで変数にア...
-
JTextFieldの入力制限
-
Javaでのジェネリクス型パラメ...
-
「IOException は対応する try ...
-
Javaで下線
-
C# 「データが失なわれる可能性...
-
「タイプ初期化子が例外をスロ...
-
エクセルVBAで、条件に一致する...
-
変数名の付け方
-
private static という変数の修飾
-
複数の変数を宣言する時、同時...
-
VB.NETでフォーム上にExcelのよ...
-
VBA コピーが出来ません…!
-
インスタンス参照でアクセスで...
-
配列の重複する値とその個数を...
-
配列のメソッド
-
コマンドプロンプト実行後に画...
-
コンボボックスのマウスホイー...
-
EXCEL VBAにて動的にCheckBOXを...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
(vba)他のアプリケーションの右...
-
C# 「データが失なわれる可能性...
-
【C#】クラスのコンストラクタ...
-
「継承されたメソッドの可視性...
-
メソッドの引数にクラス名を渡す
-
JTextFieldの入力制限
-
ASP.NETでの共通コードの書き方...
-
「ラッパークラス」の存在意義...
-
interface,extend,implementの...
-
オーバーライドとラッパーの違い
-
抽象クラスをJUNITでテストする...
-
c++でのヘッダーファイルの循環...
-
C#からDLLを呼びたいのですが・...
-
vb.net 自作プロパティの削除に...
-
ファイルパスが取得出来ない(P...
-
委譲って何ですか?
-
c# この高速化の方法あり?
-
Excel vbaのプログラムでガンマ...
-
【C#】抽象クラスでコンパイル...
-
【設計思想の質問】staticメソ...
おすすめ情報