目次
- setterとgetterのコンパイルエラーで1週間ハマった話
- 前提環境
- 文法
- 機能
- 具体的な動作内容
- 今回発生したエラー
- 原因
- 参考書籍、HP
getterとsetterのコンパイルエラーで1週間ハマった話
この記事を書くにあたってその理由となります。書き方だけ知りたい方はこの項目はスルー推奨。
現在Java言語を学習中で、プログラミング自体が初学者の者です。まずは動くものをつくる!という精神で変数はすべてpublicで記述し、オブジェクト指向は後回しにしました。
今回きっかけがあり、オブジェクト指向プログラミングでコーディングしていくこととなったのですが、setterとgetterの部分でエラーにハマり、解決までに1週間費やしました。
setterとgetterで調べても出てくるのは必要派といらない派の話ばかりで、あとは文法とか機能とかで自分のエラーについて説明しているものはなく、とても悩んだので、こうして記事を書いています。
エラー内容については後述。
前提環境
言語 Java-12.0.1
テキストエディタで記述
文法
改めて、まずはsetterとgetterの書き方から。
// 変数宣言用クラス
class SetGet{
// privateで変数宣言
private 型 変数名;
// getter
public 型 変数名{
return this.変数名;
}
// setter
public void 変数名(型 適当な変数名){
this.変数名 = 適当な変数名;
}
}
次に実行用クラスでの書き方
// 実行用クラス
class SetGetRunner{
public static void main(String[] args){
// クラスの参照変数とインスタンスの作成
// 今回の場合は クラス名 = SetGet
クラス名 参照変数 = new クラス名();
// SetGetクラスでprivate宣言した変数に値を代入
参照変数.set変数名(代入したい値);
// 値の取得
型 変数名2 = 参照変数.get変数名();
}
}
日本語で説明すると上記のような形になります。とはいえとてもわかりにくいので実際に書いてみましょう。
// getterとsetter用クラス
class SetGet2{
// privateでint型変数appleを宣言
private int apple;
// getter
public int getApple(){
return this.apple;
}
// setter
public void setApple(int apple){
this.apple = apple;
}
}
// 実行用クラス
class SetGet2Runner{
public static void main(String[] args){
// クラスの参照型変数とインスタンスの作成
SetGet2 setget2 = new SetGet2();
// privateで宣言した変数に代入
setget2.setApple(3);
// 値の取得
int appleQuantity = setget2.getApple();
// 出力
System.out.println("リンゴの個数:" + appleQuantiry + "コ");
// 出力結果
// リンゴの個数:3コ
}
}
となります。
機能
では次に機能について説明をします。
getterとsetterは
「オブジェクト指向においてインスタンス内の変数などは内部の状態を表すものであり、外部から直に参照したり操作したりすべきでないという考え方に基づく。変数などへのアクセスに必ず対応するメソッドを経由することにより、メソッド内で適切にチェックや処理を行って破綻の無いように外部からのアクセスをコントロールできるという利点がある。」
getter
「オブジェクト内部のメンバ変数(属性、プロパティ)の値を外部から読み取り・取得・参照するためのメソッド」
settter
「オブジェクト内部のメンバ変数(属性、プロパティ)の値を外部から書き込み・操作・設定するためのメソッド」
(以上IT用語辞典 e-wordsより引用)
とある。
簡単に言うと、オブジェクト指向プログラミングの考え方がつかう理由。外部からのアクセスを制限してエラーやミスを防ぐ、ということです。
getterは値を外部から得るためのメソッド、setterは外部から操作するためのメソッドです。
上記の説明から分かる通り、実は外部から操作しない場合はsetterがなくても動きます。
setterが必要になるのは外部のクラスから操作するためだけになりますので、変数をつかうだけなら必要はないわけです。
実行用クラスで行っていることも宣言クラスにあるgetterメソッドとsetterメソッドを呼び出しているだけですしね。
具体的な動作内容
具体的にそれぞれがどのように動いているのかについて前述したSetget2.javaファイルを用いて解説をします。
Setget2 setget2 = new SetGet2();
参照型変数を宣言し、インスタンスの作成することで、Setget2クラスを扱えるようになります。参照型変数やインスタンスについては、Javaで理解する場合はこちらのHPが大変わかりやすいのでご参考に。
setGet2.setApple(3);
先ほど扱えるようになった参照型変数を用いてSetGet2クラスのsetterメソッドを呼び出しています。
public void setApple(int apple){
this.apple = apple;
}
setterメソッドではこう記述されていましたね。
int appleに数値3を引数することで、SetGet2クラスの変数appleに引数した値を代入する。
というのが実行クラスの値の代入でやっていることになります。
では次に値の取得側の動きですね。
int appleQuantity = setget2.getApple();
実行用クラスでは変数appleQuantityにSetGet2クラスのgetterメソッドを呼び出して代入しています。
public int getApple(){
return this.apple;
}
ここでは戻り値があります。先ほどsetterで値を代入したappleをメソッドを用いて実行クラスに返しているんですね。その戻り値を扱う箱としてappleQuantityが宣言されて、やっと別クラスの変数を扱うことができるわけです。
ちなみに実行用クラスで再度新しい変数を宣言して別クラスの変数を用いているわけですが、式の条件にすることで変数を用いないで別クラスの変数をつかうことができます。
例えば別クラスで
private int colum;
private int row;
を宣言しているとします。setterで値を代入後、
ArrayList<Integer> data;
for(int i = 0; i < mass.getColum() * mass.getRow; i++){
this.data = new ArrayList<Integer>;
this.data.add(i);
}
とすることでそれぞれの値を変数にいれることなく用いることができます。式の結果を代入する変数は結局必要となるわけですが...。
今回発生したエラー
と、ここまで説明してやっと今回1週間ハマっていたエラー内容にたどり着きました。
エラーが発生したコードは以下になります。
class Card{
// 変数の宣言
private int mark;
private int number;
// getter setter
public int getMark(){
return this.mark;
}
public void setMark(int mark){
this. mark = mark;
}
public int getNumber(){
return this.number;
}
public void setNumber(int number){
this.number = number;
}
}
class Deck{
Card card = new Card();
card.setMark(4);
card.setNumber(13);
// 空の山札の宣言
ArrayList<Integer> deckCard = new ArrayList<Integer>();
// 山札の作成
public Create(){
for(int i = 1; i < card.getMark() * card.getNumber(); i++){
this.deckCard.add(i);
}
}
}
class Game{
public static void main(String[] args){
Deck deck = new Deck();
deck.Create();
}
}
エラー文
エラー: 型の開始が不正です
card.setMark(4);
^
エラー: <identifier>がありません
card.setMark(1);
^
エラー: 型の開始が不正です
card.setNumber(13);
^
エラー: <identifier>がありません
card.setNumber(13);
^
原因
例文と見比べればわかると思うのですが、setを
クラスにmainメソッドがないんですね。値の取得はmainメソッドのないクラスでできたのですが、値の操作はmain関数がないとできないようです。
値をあとからsetする場合はmain関数内でしかできないということを知らず、setterとgetterの文法だけをみたことが原因で1週間もの期間ハマってしまっていました。
自分のコードと参考のコードを見比べれば一発だったのにみている範囲が狭かったためのエラーですね。
みなさんもお気を付けください。
なお、なぜmainメソッドでしか実行できないかは、言語化して説明できるほと理解していないので、ほかの方に説明していただくのを待ちます。
そもそも必要あるのかないのかについても、博識な方々にお願いしようと思います。
以上、ご拝読ありがとうございます。
参考
2014年8月11日初版 中山清喬/国本大悟 著 株式会社インプレス 発行
スッキリわかるJava入門第2版
ISBN 9784-8443-3638-9
2019年7月4日アクセス 一番かんたんなJava入門
2019年7月4日アクセス Javaのオブジェクト指向入門
2019年7月4日アクセス IT用語辞典 e-word