質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

3回答

911閲覧

has-aフィールドのカプセル化について

kobe2018

総合スコア21

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2020/06/27 13:20

編集2020/06/27 13:49

前提

〇質問について
・javaのカプセル化に関する質問です。
・エラーは出ておらず、参考書のソースコードに関する疑問点です。

〇ソースコードの大まかな構成について
・Wizardクラス(魔法使い)、Wandクラス(杖)、Heroクラス(勇者)があります。
・今回、質問したいのはWizardクラスについて。
・WizardクラスはWandクラスのインスタンスをフィールドに持ちます。
・WizardクラスはHeroクラスのHpフィールド(体力)を回復させるメソッドを持ちます。
・すべてのクラスにおいて、フィールドはprivate、メソッドとクラスはpublicとします。
・すべてのクラスにおいて、ゲッターとセッターがあります。

疑問に感じること

javaの参考書で出てきたソースコードが納得いきません。
以下の2点に疑問を感じます。

①他クラスのインスタンス(wand)をWizardクラスがフィールドにもつこと。(ソースコード4行目)
Wizardクラスには他クラスのインスタンスwandがあります。
ここに文法的な違和感があります。
Wandクラスは確かにpublicです。
しかしフィールドはprivateです。
Wizardクラスのフィールドにwandを持てるものなのでしょうか。
その際、ゲッターやセッターを用いなくてよいのでしょうか。

②自分のフィールドにあるwandを取得する際にゲッターを使っていること。(ソースコード10行目)
healメソッド内でwandの値?を取得しています。
wandは確かに他クラス(Wandクラス)のフィールドですが、Wizardクラスのフィールドでもあります。なぜゲッターが必要なのでしょうか。

該当のソースコード

java

1public class Wizard { 2 private int hp; 3 private int mp; 4 private String name; 5 private Wand wand; 6 7 public void heal(Hero h) { 8 int basePoint = 10; 9 int recoverPoint = 10 (int)(basePoint * this.getWand().getPower()); 11 h.setHp(h.getHp() + recoverPoint); 12 System.out.println(h.getName() + "のHPを" + recoverPoint + "回復した!"); 13 } 14 15 public int getHp() { 16 return hp; 17 } 18 19 public void setHp(int hp) { 20 this.hp = hp; 21 } 22 23 public int getMp() { 24 return mp; 25 } 26 27 public void setMp(int mp) { 28 this.mp = mp; 29 } 30 31 public String getName() { 32 return name; 33 } 34 35 public void setName(String name) { 36 this.name = name; 37 } 38 39 public Wand getWand() { 40 return wand; 41 } 42 43 public void setWand(Wand wand) { 44 this.wand = wand; 45 } 46 47}
package sitsumon0627_1; public class Wand { private String name; private double power; public String getName() { return name; } public double getPower() { return power; } public void setName(String name) { this.name = name; } public void setPower(double power) { this.power = power; } }
package sitsumon0627_1; public class Hero { private int Hp; private String name; public int getHp() { return Hp; } public void setHp(int hp) { Hp = hp; } public String getName() { return name; } public void setName(String name) { this.name = name; } }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2020/06/27 13:27

全てのクラスを提示してください。でないとなんとも言えません。 ただ、 > インスタンスの取得にはゲッターやセッターを用いなくてよいのでしょうか。 setWand() getWand() がありますし、自身のクラスからでさえthis.getWand()と呼び出していますが、そういう話ではなくて?
Daregada

2020/06/27 13:41

「Javaの言語仕様としてできるかどうか」と、「オブジェクト指向的にやっていいことなのかどうか」のどちらについて疑問なのか、明確にされるといいかと思います。 privateのフィールドに特定のwandのインスタンスを保持しておき、なおかつアクセスには(可能な限り)ゲッター/セッターを使うことの何が疑問なんでしょうか。
kobe2018

2020/06/27 13:46

m.ts10806さん wandはWandクラスのインスタンスです。 追記しましたが、Wandクラスはフィールドのnameもpowerもprivateです。 つまりwandのフィールドを読み込んだり、書き込んだりするにはゲッターやセッターが必要です。 にもかかわらずWizardクラスでwandをフィールドに設定しているのが違和感を感じました。 ここではゲッターやセッターを用いていません。 わかりづらくてすみません。
kobe2018

2020/06/27 13:51

Daregadaさん Javaの言語使用としてできるかどうか、です。 言葉足らずですみません。 wandのインスタンスをWizardが持てることに違和感を感じました。 なぜならwandのフィールドはprivateだからです。 privateなフィールドを参照する際にはゲッターやセッターを用いるべきだと考えました。
m.ts10806

2020/06/27 13:52

> wandはWandクラスのインスタンスです。 でも、wandという変数はWizard クラスのプロパティです。 プロパティがWandという型を当てられただけです。
kobe2018

2020/06/27 13:54

すみません。プロパティをまだ理解していません。 ネットで調べてきます。
m.ts10806

2020/06/27 13:59

あごめんなさい。Javaなら「メンバ変数」と表現したほうが良かったですね。失礼しました。
Daregada

2020/06/27 14:00 編集

Wandクラスのフィールドname, powerがprivateなことと、WandクラスのインスタンスをWizardクラスのインスタンスが持てることには直接の関係はありません。Wandクラスがpublicなので、どんなクラスのインスタンスもWandクラスのインスタンスを生成して保持できます。 もちろん、Wandクラスのインスタンスを保持しているからといって、直接nameやpowerは参照できませんが、そんなことしていないでしょう? プロパティ……じゃなかった、ゲッター/セッターを通じてそれらにアクセスしているはずです。
kobe2018

2020/06/27 14:04

Wanクラスはpublic Wanフィールドはprivate そのため、フィールドにアクセスするにはゲッターやセッターが必要。 だが、インスタンスは自由に作れる。そしてその新しく作ったインスタンスのフィールドの設定はゲッターやセッター。 という認識でよろしいでしょうか。
m.ts10806

2020/06/27 14:07

一応、StringやintもWandと同じくオブジェクトですけど、ちゃんとそれらが持つ機能にアクセスできますよね。それと同じです。(雑な説明ですが)
Daregada

2020/06/27 14:17 編集

あと、確かにWizardクラスのインスタンスからは、privateなフィールドwandに直接アクセスできますが、後でwandの実装を変えたくなったときに直接アクセスしていると修正箇所が多くなります。 例えば、「実はこの世界のワンドは使い捨て。一回起動すると燃え尽きてしまうのだ。そのためにワンドは……LIFOなスタックに積んで置いて上からひとつずつ使うことになる」(後半創作力が力尽きた)なんてことになったとしても、自クラス内でgetWandとsetWandを通じてアクセスしていれば、getWandとsetWandをスタックからpop/pushするように書き替えるだけで済みますし……たぶんね。
kobe2018

2020/06/27 14:18

確かにカプセル化のメリットとして書き換えが容易というものがありました。 わかりやすい例までありがとうございます!
kobe2018

2020/06/27 14:18

お二方、ありがとうございます!
guest

回答3

0

フィールドがprivateなのにも関わらずインスタンスをWizardクラスのフィールドに持てるものなのでしょうか。

持てます。アクセス修飾子がどのようなものか確認してください。

Wizardクラスがwandをprivateで持っているのですから、privateの効力があるのはWizard以外のクラスに対してです。

java

1public class Program{ 2 public static void main(String[] args) { 3 Wizard w = new Wizard(); 4 w.setWand(new Wand()); 5 System.out.println(w.wand); //compile error 6 } 7}

なぜゲッターが必要なのでしょうか。

いいえ、必要ではありません。下記のようにしても動作します。

java

1int basePoint = 10; 2int recoverPoint = (int)(basePoint * this.wand.getPower()); 3h.setHp(h.getHp() + recoverPoint); 4System.out.println(h.getName() + "のHPを" + recoverPoint + "回復した!");

つまり、今回の場合はgetWand()を通してWandのインスタンスを取得しても、privateなフィールドを直接参照しても結果は変わりません。

投稿2020/06/27 13:30

編集2020/06/27 13:34
BluOxy

総合スコア2663

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BluOxy

2020/06/27 13:49

質問②に対する私の回答は「Javaの言語仕様としてできるかどうか」で、「オブジェクト指向的にやっていいことなのかどうか」ではありません。私ならgetterを通して取得すると思います。
kobe2018

2020/06/27 14:01

回答ありがとうございます。 オブジェクト指向的な観点ではgetterをつかうということでしょうか。 なぜ、自分のprivateなフィールドにゲッターを使うのか教えて頂けますか。
BluOxy

2020/06/27 14:28

> 私ならgetterを通して取得すると思います。 ここはあまり他意はなく、今回の場合、自分のクラスのprivateなフィールドに対して、直接値を取得・変更するのも構いません。 > なぜ、自分のprivateなフィールドにゲッターを使うのか教えて頂けますか。 フィールドは、その型通りであればどんな値でも取得・設定できます。反対に書けば、取得・設定できうるリスクがあります。ですが、privateな場合は外から変更ができませんから、安全です。しかし、値を公開したいケースがあります。 その手段がgetter/setterです。しかし、そのまま値を取得・設定できてしまうと次に意図しない利用をされるリスクが発生します。そのような場合、getter/setter内に処理を記述し、制限を設けることができます。 制限を設けることで、外部のクラスはそのクラスで公開されているgetter/setterメソッドを利用し、そのクラスの設計者が意図しないような利用を防ぐことができます。
kobe2018

2020/06/27 14:34

丁寧に回答いただき、誠にありがとうございます!
guest

0

質問の日本語の文章だけで判断したのですが、杖は魔法使いの言うことを100%聞きますか?魔法使いが杖に「粉々にくだけろ」と唱えると粉々にくだけますか?それは時と場合によると思います。そして魔法使いが杖に対して粉々にくだけていいかどうかは杖のほうで判断します。それが都合の悪い杖だと思ったら魔法使いは粉々にくだける杖に変えるだけです。

なにが言いたいかというと、魔法使いの作者と杖の作者が違うということです。オブジェクト指向におけるクラスの関係は、すべての他のクラスは他の作者が作ったものだと想定することです。package privateというアクセス修飾子もあります。それは、同じパッケージのクラスは同じ作者のものだと想定するということです。

投稿2020/06/27 13:46

anndonut

総合スコア667

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kobe2018

2020/06/27 14:34

ありがとうございます!
guest

0

ベストアンサー

①他クラスのインスタンス(wand)をWizardクラスがフィールドにもつこと。

アクセス修飾子(public,private,protected)の理解に誤解があります。

アクセス修飾子は、修飾しているクラス、メソッド、変数に対し公開範囲を指定します。
概要の説明はまずはこのリンクを読んでください。
publicな変数にはpublicなクラス、privateな変数にはprivateなクラスしか代入できないとか、そういう制限ではないことを認識してください。

②自分のフィールドにあるwandを取得する際にゲッターを使っていること。

この場合はthis.getWand()でもthis.wandでもどちらでも構わないです。結果は同じなので。しかし別の実装では同じでないかもしれません。

そもそもなぜgetter, setter を使うのか

単純にそのクラスが持つインスタンスを呼び出すだけならgetter/setterとフィールド直接参照にそれほど違いはありませんが、get/setする際に何らかの処理を行いたい場合は別です。
例えばsetWandする際、もしかしたらWizardが装備できないwandがあるかもしれないのでそれをチェックしたい場合とか、setHpする際にHp上限を超えないようにする処理などを入れたい場合があるかと思います。
getHpする際にも、本当は32000くらいHpがあるけどシステム上9999までしか表示できないので9999が返ってくるという昔のFFみたいな処理をしなければならないかもしれません。
また、もしかしたらgetter/setterに対応するフィールドがそのクラスに存在しないかもしれません。実はHPは無限なので常にgetHpは9999を返すとか。

例のクラス構成ではあまりピンとこないかもしれませんが、クラス内の構造を気にせずgetter/setterを使えば目的の情報が得られるということは今後出てくるであろう「継承」や「カプセル化」の概念を学習するときに重要になります。

投稿2020/06/27 14:19

hope_mucci

総合スコア4447

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kobe2018

2020/06/27 14:37

アクセス修飾子に誤解がありました。 private、publicは公開範囲。 そしてその対象はクラス、フィールド、メソッドそれぞれにあるということ。 私はこの3つを混同してました。 またなぜゲッターやセッターを用いるかもわかりやすい例で回答いただき、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問