ここから本文です

コンストラクタについて。

gan********さん

2019/8/1723:40:52

コンストラクタについて。

こんばんは、最近javaの質問投稿しまくっててすみません。今回はコンストラクタについて質問があります。

Humanクラス

フィールド
String name;
int age;

コンストラクタ
Human(String name , int age){
this.name = name;
this.age = age;
}

別クラスでインスタンス作成
Human h = new Human("田中",22);

するとフィールドのname="田中" age=22
で使用することが出来る...ってことですよね?

コンストラクタを学習して思ったことは、初期化の時点で引数の値をフィールドの値にセットできるなら楽になりそうだなーと思ったぐらいでした。
でもコンストラクタがなくても変数の初期化って出来ますよね?コンストラクタが存在する理由が、引数に応じて初期化処理を自動でしてくれる以外のメリットが分かりません。

また、例えばHumanクラスのインスタンスの引数にboolean型(男性or女性など?)をもたせたとき、コンストラクタの中でif文を用いて条件分けを行い、インスタンス作成直後にtrue or falseを識別することも可能なのでしょうか?


考え違いや、「いやいやお前はコンストラクタの重要なことを見逃している」と思われた方、是非教えてください。
よろしくお願いします。

閲覧数:
30
回答数:
4
お礼:
100枚

違反報告

ベストアンサーに選ばれた回答

プロフィール画像

カテゴリマスター

n2q********さん

2019/8/1809:52:19

『初期化の時点で引数の値をフィールドの値にセットできるなら楽』

そうお考えの方は沢山居らっしゃると思います。
でも、次のようにすると印象が変わるかもしれません。


final String name;
final int age;


『コンストラクタがなくても変数の初期化って出来ますよね?』

上記のようにするとそれが出来なくなります。
後で名前や年齢を変えることもご法度となります。



『コンストラクタが存在する理由が、引数に応じて初期化処理を自動でしてくれる以外のメリットが分かりません』

オブジェクトが生成される際に規律を与えます。無造作にオブジェクトが生成されて、事後的に値を設定しようという、そういう発想ではないわけです。

バグは混沌の中に発生します。秩序によりそれを防ぐことが出来るんですね。では、秩序はどのようにしてもたらされるのか。

それは規律。



『例えばHumanクラスのインスタンスの引数にboolean型(男性or女性など?)をもたせたとき、コンストラクタの中でif文を用いて条件分けを行い、インスタンス作成直後にtrue or falseを識別することも可能なのでしょうか?


まずはご自身で試してみて、何らかの問題が発生したところで、あるいは何らかの疑問が生じたところでお尋ね頂くと良いような気がしました。

何故かと言いますと、お尋ねの文面と、本当にご自身としてお考えになった実現内容との関係性がちょっと見えないので。

ベストアンサー以外の回答

1〜3件/3件中

並び替え:回答日時の
新しい順
|古い順

プロフィール画像

カテゴリマスター

ikt********さん

2019/8/1807:10:46

>コンストラクタがなくても変数の初期化って出来ますよね?

コンストラクタじゃないと初期化できない状況も、存在します。
たとえば、意図的に
・不変(immutable) なクラス
を作るとき。
有名(?)な例としては java.lang.String
興味あるなら、
Java 不変クラス
の2語でネット検索してみてください。

>コンストラクタが存在する理由が、引数に応じて初期化処理を自動でしてくれる以外のメリットが分かりません。

私は、コンストラクタ のいちばんの存在理由は
・インスタンス生成と不可分一体であること
と思っています。

インスタンスは new 演算子でしか、生まれません。
new の前は存在せず、newの完了直後に初めておぎゃーと生まれます。
コンストラクタは new の処理過程・途中で呼び出されてますが、
new の利用者側から見れば不可分一体です。
コンストラクタが呼ばれる前にインスタンスにアクセスすることはできない。
生まれたインスタンスにアクセスできるのはnew後であって、そのときは
必ずコンストラクタは処理を終えています。

利用者コードが new Human する時点で、名前・年齢 を確定できるのなら
Human h = new Human(name, age);
のほうが、
Human h = new Human();
h.setName(name);
h.setAge(age);
よりも、よいです。
前者は、名前も年齢も未セットな状態な h にアクセスできる ことは
起こりえないが、後者では可です。
可能な スキマ があるわけで、そんなハンパな状態でインスタンスに
アクセスするかしないかはすべて利用者側に依存する。
// new後 set... を呼ぶまでの狭間が スキマ 区間
Humanクラス自体が、関与・保証 できません。

また、たとえば、
・name は nullや空文字列 はありえない、必ず1文字以上の有効文字を持つ
・age は 必ず正の整数であって、負数はありえません
といった内容を事後条件として Human クラス自体が保証したい場合、
コンストラクタならば可能です。
コンストラクタ内で引数チェックし、条件外な値であったなら assert
したり例外をthrowしたり。
おぎゃー と無事生まれたHumanインスタンスは、必ず保証された
name や age を持つことが、保証されることになります。
利用者の使い方によって... というあいまいさは、発生しません。



伝わるかどうかわかりませんが、
・コンストラクタでしかできないことはある
・コンストラクタは、なんらかの利便性がある便利オマケとして存在するわけでない
ことは、ご理解いただきたい。

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

プロフィール画像

カテゴリマスター

あみやさん

2019/8/1802:35:33

オブジェクト指向では、データを中心に物事を考えます。
まずはデータがありきで、そのデータに様々な機能が付随しているというふうに考えるのです。
コンストラクタで指定するのは、そのコアとなるデータです。

この場合は、名前と年齢のデータがオブジェクト(インスタンス)の本体となります。
逆に言うと、そのデータが無い=本体の存在しない、空っぽのインスタンスは存在してはいけないのです。

クラスがインスタンスを形作る為の鋳型だとするなら、
コンストラクタで与えるデータは、その鋳型に流し込む素材そのものです。
物体は、鋳型に素材を流し込んで固めることで、初めて形になります。

インスタンスはデータを入れる入れ物ではなく、データ本体だと思ったほうが分かりやすいかもしれません。

Human h = new Human("田中",22);
とした場合、Humanは入れ物の形で、hが入れ物です。
そこに、newで作られた実体=インスタンスが入れられます。

これを普通の変数に置き換えると、
int a = 4;
intが入れ物の形、aが入れ物、4がそこに入れられるデータです。

こうやって並べるとインスタンスはデータを拡張したものであるって見えてくると思います。

String s = new String("Hello");
を略して
String s = "Hello";
と書けるように

Human h = new Human("田中",22);

Human h = {"田中",22};
みたいに、書けるようになったら、より分かりやすくなりそう
(実際にはこれはできません)


言語レベルの話では、コンストラクタで初期値を設定する事を義務付ける事で、
最低限、何らかの値は入っている事を前提として、他の部分を組めるというメリットがあります。
フィールドに直接アクセスはさせずアクセサメソッドを仲介させたりするのが良いとされるのも、
フィールドの値の有効性をオブジェクト自身がしっかり保証するための仕組みです。

efb********さん

2019/8/1801:07:56

以後私の見解なので、思ってらっしゃることと違うかもしれませんが、参考程度に。
>>Humanクラスのインスタンスの引数にboolean型(男性or女性など?)をもたせたとき、コンストラクタの中でif文を用いて条件分けを行い、インスタンス作成直後にtrue or falseを識別することも可能なのでしょうか?

→できるとおもいますよ!
例)
class Human{
char sei;
Human(boolean seibetsu){
if(seibetsu){
this.sei='男';
}else{
this.sei='女';
}
}
}

こんな感じでしょうか?


>>コンストラクタが存在する理由が、引数に応じて初期化処理を自動でしてくれる以外のメリットが分かりません。

→自分も昔までは(ついこの間までは)コンストラクタの存在価値が分かっていませんでしたが、GUIを勉強すると良く分かりました。もし以下の説明で分からなければGUIを勉強してみてください。(ちなみに自分はswingです)

例①GUI(swing)での例
swingでの画面の表示窓(いわゆるウィンドウ)はJFrameというクラスを使います。なのでひとつウィンドウ(以下フレーム)を作る処理は以下の通りになります。
JFrame f = new JFrame();
ただ、これだけだとなにも起こりません。なぜかというと、JFrameクラス(のインスタンス)にはboolean 型のvisibleという変数があり、これがtrueではないと表示されません。なので、setVisibleメソッドでtrueをセットします。これをまとめると、フレームを作る処理は以下の通りになります。
JFrame f = new JFrame();
//インスタンス作成
f.setVisible(true);
//visibleにtrueが入る

JFrameクラスにはさらに、大きさを変えたり、背景の色を設定したり、閉じたときの処理を決めたりするメソッドが用意されていますが、これを呼び出す側でいちいち設定するのは面倒でコードが見にくくなってしまいます。(上の例で言うと、4行目のあとにf.大きさ変更メソッド();...と続く)なので、普通、自分でJFrameを継承して新たなフレームのクラス(MyFrameなど)を作り、そのコンストラクタにsetVisibleメソッド、大きさを変えるメソッドなどを設定することで、インスタンスを作成する側では作ったクラスのインスタンスを作るだけで自動的に画面に表示されるまで、設定を施せるのです。要するにprivateなフィールドを含むクラスを継承したときに初期値を設定したいときに、それを設定できるのはセッターメソッドだけだから、それを使うため、ということです。

例②遊戯王風に...
例えば、あなたがカードゲーム(遊戯王などの部類)を作るとして、その途中、登場したときに敵一体の攻撃力を-500するSuperMonsterクラスを作るとします。(なお、モンスターカードなどのインスタンスはカードが召喚されたときに生成するものとします。)
コンストラクタがないと、場に出たときに(=インスタンス化されたときに)呼び出し側で攻撃力を-500するメソッドを書かなければならないので、開発者が書き忘れた時におかしいことになってしまいます。なので、インスタンスが作られたときに必ず実行して欲しい処理(特にメソッド)を行えるようにコンストラクタが用意されています。


二つをまとめると、
コンストラクタは、初期化というよりは、初期化をしたい変数が継承元のprivateな変数でありそれを初期化したい時にセッターメソッドを使いたいときや、インスタンス生成時に必ず行って欲しいメソッドを呼び出すためにjavaに用意されているもの。これがあることで、インスタンス化時にフィールドの初期化("int power = 10"の= 10)だけでなく、メソッドも呼び出せるようにあるもの。
ということができる気がします。

あわせて知りたい

みんなで作る知恵袋 悩みや疑問、なんでも気軽にきいちゃおう!

Q&Aをキーワードで検索:

Yahoo! JAPANは、回答に記載された内容の信ぴょう性、正確性を保証しておりません。
お客様自身の責任と判断で、ご利用ください。
本文はここまでです このページの先頭へ

「追加する」ボタンを押してください。

閉じる

※知恵コレクションに追加された質問は選択されたID/ニックネームのMy知恵袋で確認できます。

不適切な投稿でないことを報告しました。

閉じる