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

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

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

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

Q&A

解決済

13回答

24174閲覧

Javaのsetterとgetterの意義について

frippy

総合スコア17

Java

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

2グッド

5クリップ

投稿2015/03/30 00:54

編集2016/03/16 05:40

Javaで実装するときに、以下のようにフィールドをprivateにしてsetterとgetterを実装するということがあるかと思います。

lang

1public class Product { 2 private String name; 3 private Integer price; 4 public String getName() { 5 return name; 6 } 7 public void setName(String name) { 8 this.name = name; 9 } 10 public Integer getPrice() { 11 return price; 12 } 13 public void setPrice(Integer price) { 14 this.price = price; 15 } 16}

最初にこれを見たときは、わざわざフィールドをprivateにしてsetterとgetterを実装する意味が分からず、以下のようにフィールドをpublicで実装してしまった方がコードも短くなって読みやすいのではないかと思いました。

lang

1public class Product { 2 public String name; 3 public Integer price; 4}

その後も、Javaでsetterとgetterを実装する理由について、周りのエンジニアの方々に質問したり、ググったりしてみたのですが、「Javaの仕様だから」、「オブジェクト指向だから」というような回答が多く、なかなか納得できる答えに出会えませんでした。

今では、私自身もなんとなくsetterとgetterを実装する習慣が付いてしまっているのですが、それでもsetterとgetterを実装する実質的なメリットはよく分かっていません。

この辺りの話題に詳しい方がいらっしゃったら、setterとgetterの意義について教えて頂けるとありがたいです。

よろしくお願い致します。

lib, ikuwow👍を押しています

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

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

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

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

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

guest

回答13

0

発想としては、「外部に公開する仕様を、内部の実装とは関係なく決め打ちにできてしまう」ということがあります。

たとえば、メンバ変数として特定のルールに従った値を要求する場合、パブリックでそのまま代入するとその値を使う時点でしかチェックできませんが、setterを使えばその段階でチェックが可能となります。

また、変数という形では時々刻々と変わる値をその都度取得する、というような処理は実現することはできませんが、getterとすれば特に問題がありませんし、内部的に「処理して取得するもの」と「変数として持っているもの」とを区別することなく、外部から使えるようになります。

なお、C#やRubyなど、外から見れば変数代入に見えるけど、内部的にはアクセサを動作させるというような形で、明示的にアクセサを呼びださなくて済むようにした言語もあります。

投稿2015/03/30 02:01

maisumakun

総合スコア145121

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

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

0

このクラスに限って,あるいは,このような単純な情報の出し入れだけだったらおっしゃるようにgetter/setterを設けるメリットはないのかもしれません.
しかし,もっと多くの情報を扱うクラスで,他のクラスから勝手に操作されたくない情報というのはほぼ確実に出てきます.
例えば,Exceptionクラスには「原因」となるThrowableオブジェクトを格納するフィールドがあります.この仕組み上,1回原因を設定したあとは変更を加えられるのは望ましい状態であるとは言えません.このため,initCause(Throwable)というメソッドがあります.setで始まりませんが,実質setterです.
すでにこのメソッドで原因を入れていたり,Exceptionのコンストラクタで原因を入れていたりした場合は例外を発生させる仕組みになっています.

そして,このようなgetter/setter"だけ"を設けた場合,どのフィールドに対してgetter/setterを付けたか,付けなかったかをいちいち考えてプログラムしなければならず,非常に使いづらいクラスになるでしょう.それなら全てにgetter/setterを設けて,アクセス方法を統一したほうがわかりやすいですし,ミスも減ると思います.

投稿2015/03/30 03:24

swordone

総合スコア20649

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

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

0

私も深く理解している訳ではないのですが、JavaBeansに即してではないかと思います。

JavaBeansのルールを知る

以下の用途でJavaClassを使用する場合、getter/setterは必須になります。

・JSPのページからJavaClassをアクセスする
・JSFのBackingBean実装
・JavaEEにてDBアクセス用にModel(EntitiyBean)を作成する

フレームワークやライブラリを利用する際、スクリプトの記載からsetter名/getter名に変換
してインターフェースとする用法が多いようです。

投稿2015/03/30 03:09

BlueMoon

総合スコア1339

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

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

0

getterとsetterがあることによって、例えば、下記のようにpriceに0以下の値をセットすることを禁止したりもできます。
もし、フィールドがpublicだったらこのような拡張ができませんね。

Java

1public class Product { 2 private String name; 3 private Integer price; 4 public String getName() { 5 return name; 6 } 7 public void setName(String name) { 8 this.name = name; 9 } 10 public Integer getPrice() { 11 return price; 12 } 13 public void setPrice(Integer price) { 14 if (price.intValue() >= 0) 15 // priceが0以上の場合はそのまま代入 16 this.price = price; 17 } else { 18 // 0以下の場合は例外をスローする 19 throw new HogeException("price is NOT positive number."); 20 } 21 } 22} 23```

投稿2016/03/13 14:52

編集2016/03/13 14:55
Odacchi

総合スコア907

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

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

frippy

2016/03/16 05:37

ありがとうございます。たしかに、バリデーションを追加したいときなどは、setterにしたメリットが分かりやすく現れますね。
guest

0

以前も同じような質問があったので、一応載せておきます。

https://teratail.com/questions/2863

投稿2015/03/31 07:44

k.tada

総合スコア1679

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

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

frippy

2015/03/31 14:22

ご指摘ありがとうございます! こちらのやり取りも参考にさせて頂きます。
guest

0

はっきり言ってしまえば、getter/setterを書く方法と、当該フィールドをpublicにする方法とは、一長一短があり、議論の対象です。Kent Beckの「Smalltalkベストプラクティスパターン」などでも、両方の流儀の良さを述べていたと記憶します。

しかし、ことJavaに限っていれば、getter/setterを書く方法が主流であり、ほぼ議論の余地はありません。これは単純にJava Bean仕様によってそのように決めたので、特別な事情のないかぎり、その仕様に従っておく、ということが慣例になっているということです。

投稿2015/03/30 07:43

chokojori

総合スコア971

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

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

chokojori

2015/03/30 07:47

もうちょっと補足するとリフレクションを簡単に使うための工夫です。 getter/setterを書くことにしておけば、getMethods()することでgetter/setterも入手できます。しかし、getter/setterを書かない場合はgetFields()しなければなりません。リフレクションを使うときの手間が大きく違いますね。
frippy

2015/03/31 14:33

回答ありがとうございます。 >>リフレクションを使うときの手間が大きく違いますね。 すみません。 この辺りが無知なので、もう少し詳しく教えて頂けるとありがたいです。 例えば、 public class Product1 { public String name; public Integer price; } というクラスと public class Product2 { private String name; private Integer price; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getPrice() { return price; } public void setPrice(Integer price) { this.price = price; } } というクラスがあるとします。 このとき、以下のように、Product1に関してはgetFields()を使って、Product2に関しては getMethods()を使えば、どちらでもリフレクションが可能かと思います。 public class Main { public static void main(String[] args) throws ClassNotFoundException { for(Field field : Product1.class.getFields()) { System.out.println(field.getName()); /* * <出力結果> * name * price */ } for(Method method : Product2.class.getMethods()) { System.out.println(method.getName()); /* * <出力結果> * * getName * setName * getPrice * setPrice * wait * wait * wait * equals * toString * hashCode * getClass * notify * notifyAll */ } } } >> 手間が大きく違う というのは、どのような場面でリフレクションを使用する場合のことを想定しているのか、教えて頂けるとありがたいです。 よろしくお願いします。
chokojori

2015/03/31 20:10

getMethods()とgetFields()の両方を扱うより、getMethods()だけを扱う方が手間が小さいです。半分以下になりますね。 また、リフレクションを使うのは、メソッドやフィールドの名前を取得するだけでなく、そこからユーザにそれを示したり、設定ファイルと突き合わせたりして、実際にいずれかのメソッドやフィールドにアクセスすることになると思いますが、そのときもメソッドとフィールドでは、ユーザに選択肢として表示するにも、実際にアクセスするときにも、それぞれに行なう必要がありますね。
guest

0

確かにオブジェクト指向だからと言われるとわからないですよね。
基本的には以下のようなメリットがあるからでしょうか。
・オブジェクトの呼び出し元はオブジェクトの状態を意識せずに扱える。
→getterやsetterを定義するルールにしておけば、統一がしやすいってこともありますね
・オブジェクト内でしか使わない情報を隠せる。
→そのフィールドを他の処理でも使う場合などに直接アクセスされると困る場合など
・呼び出し元を意識せずに変更がしやすい。
→呼び出し元が知っているのはgetterとsetterだけなので、実際のgetterとsetterの処理が変更しやすい
・継承などを行ってもアクセスの方法が変わらない。
→継承先のsetterやgetterの処理を変えることもできる。

また、基本的にはオブジェクト間はメッセージをやりとりするような感覚で扱うので、
例えば、Aという人を表すオブジェクトに対して、「Aさん、名前!」というより「Aさん、名前を教えて!」という方が自然に扱えるからというのも考え方の一つとしてあっても良いかもしれません。

投稿2015/03/30 06:01

hiroki8080

総合スコア254

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

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

0

他の言語から Java を見た場合の意見です。

Java は getter/setter(メソッド呼び出し)とフィールドアクセスの記法を揃えられません。
そのことから書き方を揃えるために getter/setter に寄せるのが一般的になっているのではないかと思います。

メソッド(getter/setter)とフィールドアクセスの違いは、アクセス時に処理をいれこめるかどうかの違いです。
単に値を運ぶだけならフィールドアクセスで良いのですが、必要時に計算して得る値となるとメソッドで実装するしかありません。

メソッドとフィールドアクセスには明確な構文の違いがあります。

value = a.getField();
a.setField(value);

value = a.field;
a.field = value;

この2つを混在させたくないから getter/setter に寄せるのではないかと思います。
1つに統一したいのはなぜかというと、

・単純に全体の統一感を維持したいから。
・もしも処理が必要になったときに、メソッドに変更するしかなく、その場合は全てのアクセス箇所を書き換える必要が出てくる。

というのが主な理由だと思います。

これが他の言語になると話は変わってきます。

getter/setter 定義用の専用の構文が用意されていて、
getter/setter とフィールドアクセスの書き方が統一されていて切り替え可能になっていたりします。
スクリプト言語である Ruby や C# なんかでも使えます。Java の派生言語である Scala なんかでも使えたような気がします。

そうした場合は段階的に最初はフィールドを直接アクセスさせておいて、必要になったら getter/setter に書き換えるということがしやすいです。

Java はそれがしずらいので、そろえるなら getter/setter にそろえるというのが一般的になっているように思います。

投稿2015/03/30 04:00

toydev

総合スコア297

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

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

0

クラスのプロパティに対するsetterメソッド(ミューテータ)、getterメソッド(アクセサ)の存在理由としては、そのクラスのプロパティを別のクラスから利用できるのがgetterだけ、つまり内容を取得するのを許可し、setterは許可しない、のように利用制限するために用います。

ただ単純にデータベースの検索結果や画面からの入力項目を格納する目的のクラス(DataTransferObjectと呼称されているものです)ならば、常にgetter/setterを両方使いますので、これらのメソッドは不要で、public化しても特に大きな問題にならないでしょう。

投稿2016/03/15 06:15

A-pZ

総合スコア12011

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

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

frippy

2016/03/16 05:35

ありがとうございます!非常に明快に説明して頂き、腑に落ちました。
guest

0

ベストアンサー

Javaに限ってのお話ですが、他の方が答えられているように、大半は、JavaBeansの仕様に従っているだけだと思います。
他のオブジェクトから操作されたくないような場合は、getterはまだしも、setterに関しては、この記事にあるように、単純に薄っぺらいラッパーではなく、別のかたちのメソッドになるように思えます。

また、インスタンスフィールドを公開しない理由としては、疎結合にするというのもあります。
疎結合にすることで、JMockitなどで、クラスをMock化する際に、accessorメソッドがあった方が、Mock化しやすいという利点もありますが、現実には、インスタンスフィールドを直接書き換えるなんて、リフレクションを使わない限りは、初心者くらい(バグ出しそうで、怖くて、普通はやらない)だと思うので、コンストラクターで初期化して、書き換えないような場合はpublic final、リフレクションで初期化してから使われるような場合は、publicにして公開してしまったりしています。

Javaの定石では、accessor(setter/getter)を用意するのですが、不要であれば直接公開もあり と言ったところでしょうか?

投稿2015/03/30 15:36

編集2015/03/31 04:04
poad1010

総合スコア30

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

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

frippy

2015/03/31 14:55

回答ありがとうございます! >>コンストラクターで初期化して、書き換えないような場合はpublic final 例えば以下のような感じですね。 public class Product { public final String name; public final Integer price; public Product(String name, Integer price) { this.name = name; this.price = price; } } こういう実装は今まで気づかなかったので、目から鱗です。 ありがとうございます!
guest

0

カプセル化。
基本的にインスタンス変数は公開してはいけません。
どこでどうかえられたか管理できず煩雑になるため。
Beanのようなクラスではメリットはあまり見受けられないと思いますが、
Interfaceなどスコープを小さくする場合にメリットがあると思います。

投稿2015/03/30 15:05

ManabuHayashi

総合スコア17

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

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

0

例えばDBと連携する自前のクラスを作るとします。そのクラス内にDBのオブジェクトをprivateな変数として持っておけば、そのクラス内からしか操作されない事が保証されますよね?
そうする事でprivateの意味が出てくるんじゃないかな?
カプセル化とか隠ぺいとかよく言われてるけど、プログラマー同士のメッセージ的な意味だと自分では思っています。

投稿2015/03/30 13:29

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

退会済みユーザー

退会済みユーザー

2015/03/30 13:38

でもDBオブジェクトのgetter、setterあったら外でちゃうから意味ない(笑) 回答になってなかった
guest

0

私もあまり詳しいわけではありませんが、
オブジェクト指向のカプセル化という考え方に関係あると認識しています。

全てpublicのメンバ変数だと、外部で何か修正が加わった際にクラスの仕様をよくわかってない人が
入れてはいけない場所に入れてはいけない値を入れてしまうリスクが発生してしまいます
数値を期待している変数なのに文字列を突っ込んでしまうとか…
まずはAという変数に値を入れて、処理結果がBに入るのに、いきなりBに代入してしまうとか…

期待していない変数にいきなり文字列を突っ込まれて
「あれ?エラー…。ここで文字列を数値に変換してやる必要があるんじゃね?あれ、今度はこっちでエラー…じゃぁここをこうして…」
などと、クラスの仕様を理解してない人がコードを引っ掻き回して、せっかくきっちり作っていたのにソースコードがボロボロになってしまうかもしれません。

そういった場合もprivateでとっておけば、セッターがなければ代入できませんし、
セッターを通していれば、セットする段階で型などを判定してやればよいです
また、そういうコードをアクセサに仕込んであれば、あとでこのクラスを使おうと思った人が見たとき、
「あ、このアクセサには数値が入ることを期待しているんだな」とかわかりやすいと思います

多人数で大きなシステムを開発する上で非常に重要なのではないかなと思います

投稿2015/03/30 06:37

yokoyam49

総合スコア23

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問