2014年10月8日水曜日

- コンストラクタ - Java

前回の「インスタンスとクラス」の補足。

補足といっても、内容は非常に重要なため、しっかり理解しておきたい。

コンストラクタとは…

new と同時に(インスタンス化)、実行されるメソッドのこと。

定義の決まりごとは
・メソッド名がクラス名と一致
・戻り値を記述しない
(コンストラクタが実行される際に渡して欲しい引数を、newするときに指定すればよい)



package blog;

public class Tomomi {

 int age;
 int mana;

 // インスタンス化(new)された直後に実行される処理を書いたメソッド
 Tomomi(){
  this.mana = 20;
  System.out.println("起きてすぐのマナの残量は"+ this.mana + "です");
 }

 // 引数を受け取る
 void study(int time){
  this.mana -= time;
  System.out.println("勉強して、マナが"+ this.mana + "になった" );
 }
 // 引数を受け取る
 void sleep (int time){
  this.mana += time;
  System.out.println("寝て、マナが"+ this.mana + "になった" );
 }
}

package blog;

public class main {

 public static void main (String []args){

  // インスタンス化
  Tomomi t = new Tomomi();

  // 引数を渡して、呼び出して実行
  t.study(9);
  t.sleep(7);
 }
}










Tomomi クラスの
 Tomomi( ) {

}
が、コンストラクトになっている。
これを見て、わかるように、コンストラクタは、mainクラスから、
newされるときに必ず最初に自動で実行される。
他のメソッドのように、直接呼び出すメソッドではない。

ただ、直接、情報を渡すこともできる。
定義の決まりごとの部分に、少し書いてある
「コンストラクタが実行される際に渡して欲しい引数を、newするときに指定すればよい」
これが、どういうことか実際にみてみると


package blog;

public class Tomomi {

 int age;
 int mana;

 // インスタンス化(new)された直後に実行される処理を書いたメソッド
 // newする際に、int型の引数を受け取る
 Tomomi(int mana){
  // 受け取った引数を フィールド変数 mana に代入
  this.mana = mana;
  System.out.println("起きてすぐのマナの残量は"+ this.mana + "です");
 }

 // 引数を受け取る
 void study(int time){
  this.mana -= time;
  System.out.println("勉強して、マナが"+ this.mana + "になった" );
 }
 // 引数を受け取る
 void sleep (int time){
  this.mana += time;
  System.out.println("寝て、マナが"+ this.mana + "になった" );
 }
}

package blog;

public class main {

 public static void main (String []args){

  // インスタンス化して、コンストラクタに情報を渡す
  Tomomi t = new Tomomi(20);

  // 引数を渡して、呼び出して実行
  t.study(9);
  t.sleep(7);
 }
}

実行結果はさきほどと、変わらない。

コンストラクタのオーバーロード

上の例を見返してみる。

Tomomiクラスは、int型の引数を1つ受け取るように定義されている。
(int型の引数が必ず必要!!)

しかし、同じ名前のクラスを、同時に定義できる。
以前、学んだ、オーバーロードを使う。



package blog;

public class Tomomi {

 int age;
 int mana;

 // インスタンス化(new)された直後に実行される処理を書いたメソッド
 // newする際に、int型の引数を受け取る
 Tomomi(int mana){
  // 受け取った引数を フィールド変数 mana に代入
  this.mana = mana;
  System.out.println("起きてすぐのマナの残量は"+ this.mana + "です");
 }

 // 引数を受け取らない
 Tomomi(){

  this.mana = 10;
  System.out.println("普段のマナの残量は" + this.mana + "です");
 }

 // 引数を受け取る
 void study(int time){
  this.mana -= time;
  System.out.println("勉強して、マナが"+ this.mana + "になった" );
 }
 // 引数を受け取る
 void sleep (int time){
  this.mana += time;
  System.out.println("寝て、マナが"+ this.mana + "になった" );
 }
}


package blog;

public class main {

 public static void main (String []args){

  // インスタンス化
  // 引数がないので、引数を受け取らないコンストラクタが呼び出される
  Tomomi t = new Tomomi();

  // 引数を渡して、呼び出して実行
  t.study(9);
  t.sleep(7);
 }
}










また、クラスは、インスタンス化するときに、何かしらのコンストラクタを実行する。
が、特例がある。
クラスに1つもコンストラクタが定義されていない場合は、
「引数なし、処理内容なし」のコンストラクタの定義が自動的に追加される。
(クラスとインスタンスのときに書いていたものが、これに該当する)


コンストラクタから、別のコンストラクタを呼び出す

重複する処理を使いたい場合など、別のコンストラクタから呼び出すことができる。


package blog;

public class Tomomi {

 int age;
 int mana;
 String name;

 // インスタンス化(new)された直後に実行される処理を書いたメソッド
 // newする際に、int型の引数を受け取る
 Tomomi(String name){
  // 受け取った引数を フィールド変数 mana に代入
  this.mana = mana;
  this.name = name;

  System.out.println("起きてすぐのマナの残量は"+ this.mana + "です");
  System.out.println(this.name + "1");
 }

 // 引数を受け取らない
 Tomomi(){
  // Tomomi(String name)のほうのコンストラクタを呼び出す
  this("ともみ");

  this.mana = 10;
  System.out.println("普段のマナの残量は" + this.mana + "です");
  System.out.println(this.name + "2");
 }
}

package blog;

public class main {

 public static void main (String []args){

  // インスタンス化
  // 引数がないので、引数を受け取らないコンストラクタが呼び出される
  Tomomi t = new Tomomi();

 }
}









わかりやすいように、コンストラクタの中の実行文に数字を入れた。

this("ともみ")
で、1つ目のコンストラクタは文字列「ともみ」を受け取って実行している。

注意点は
thisの後にクラス名ではなく、引数を書く!!


2014年10月3日金曜日

- インスタンスとクラス - Java

自分が神様となって、現実世界を真似た仮想世界に、互いに連携し合って動くオブジェクトを生み出す!!

オブジェクト指向の概要はなんとなく理解した。

我々が実際にやることは……













ここで注意点!!!

定義といっても、オブジェクトそのものを定義することは出来ない!!!










クラスを定義!!!

そこから、オブジェクトが生まれる!!!
































この例では、三つだからいいけれど、もし、クラス=オブジェクトだとしたら……
カップヌードル、綾波レイを大量に作ることになったらクラスが増えすぎてしまいますね!


このオブジェクトを インスタンス といい、
クラスから、インスタンスを生成することを インスタンス化 という。


仮想世界を作ってみよう

オブジェクト指向の時に、例に出した「うちの近所の争い」を作ってみます。
題して、「ヴァーチャル近所!!」

















きちんとしたクラス図(世界共通の設計図の1つ)で描くと












(名前がないとわかりづらいので、属性に name を追加しました)
ぱっと思いつくクラスはこの三つ。

・野良猫クラス
・餌やりおばちゃんクラス
・隣のおばちゃんクラス

が、しかし、これだけでは足りない!
指示(呼び出し)がないと、この三つのクラスは動かない。
指示を与えるクラスが必要。
創造主である自分の指示を書くためのクラスですね。
それが、 main クラスになる。

まずは、 mainクラス以外を作っていく。


























では、操作が少ない、「NextHouseLady」(隣のおばちゃん)クラスを書いていく。

①クラスの宣言

これは、今のところ特に難しいことはない。


public class NextHouseLady {

}


これだけ。わたしは、eclipseを使っているから、自分では書いてない。

②属性の宣言

作ったクラスブロックの中に、属性を書いていく。
隣のおばちゃんだと、属性は2つ。

・String type
・String name



package blog;

public class NextHouseLady {

 // 属性の定義
 String type;

 String name;
}


今までやってきた、変数宣言と変わらない。
(クラスブロック内に宣言された変数は フィールド という)
そして、今まで同様、宣言と代入は同時に行うことが出来る。



package blog;

public class NextHouseLady {

 // 属性の定義
 String type = "human";

 String name = "隣のおばちゃん";
}

また、「隣のおばちゃん」は、今後、何十年かたつと、「隣のおばあちゃん」になるかもしれないけれど、「人間」でなくなることは決してない。
一生、 String type = "human";
である!だから、書き換えられないようにしたい場合も変数と同様、
 final をつけておけばいい。
(定数フィールドという)


package blog;

public class NextHouseLady {

 // 属性の定義
 final String type = "human";

 String name = "隣のおばちゃん";
}

これで、属性の宣言は完了。

③操作の宣言

「隣のおばちゃん」の操作はたった一つ。
rage(怒る)だけ。
これを、メソッドにする。

package blog;

public class NextHouseLady {

 // 属性の定義
 final String type = "human";

 String name = "隣のおばちゃん";

 // 操作の定義を記述していく
 void rage() {
  System.out.println("激怒した");
 }
}

簡単に書くとこれだけ。
ただ、せっかく、名前があるから
「隣のおばちゃんは激怒した」
にしたい。

その場合は、


package blog;

public class NextHouseLady {

 // 属性の定義
 final String type = "human";

 String name = "隣のおばちゃん";

 // 操作の定義を記述していく
 void rage() {
  System.out.println(this.name + "は、激怒した");
 }
}


こうなる。
今までだと
System.out.println(name + "は、激怒した");
これでも、動くけれど、
ローカル変数、引数に同じ名前(name)があった場合に、予期せぬバグが出る原因になる。
だから、必ず、フィールドを扱うときは

this.フィールド名

にしなければいけない。
この「this」は、 自分自身のインスタンス という意味がなり
「.(ドット)」は英語では「of」、日本語では「~の」という意味になる。

これで、簡単なクラスの定義は完了。


mainクラス

クラスの定義が終わったので、mainクラスに指示を書いていく。
上にも書いたように、今はまだ、指示を出す mainクラス が書かれていないため、プログラムは動かない。

次は、 StrayCat(野良猫)クラスに対して、指示を与えていく。

StrayCat に新たに int型のフィールド hungry(空腹度を表す) を追加した。


package neighborhood;

public class StrayCat {

 // 属性の定義
 String type;
 final String name = "野良猫ちゃん";

 // 空腹度
 int hungry;

 // 操作の定義を記述していく

 void cadge() {
  System.out.println(this.name + "は、餌をねだった");
 }

 void eat() {
  System.out.println(this.name + "は、餌を食べた");
  hungry = hungry - 3;
  System.out.println(this.name + "の空腹度は" + this.hungry + "になった");
 }

 void escape() {
  System.out.println(this.name + "は、逃げていった");
 }
}


mainクラスでやりたいことは

① 野良猫を誕生させる
② 野良猫に、空腹度を設定する
③ 野良猫に、「ねだる」、「食べる」、「逃げる」指示を出す

上から順に書いていく。

まず、① 野良猫を誕生させる
というのが、どういうことかというと、
上で、クラスから生成されるのが、オブジェクトで、それをインスタンスという、と説明したように
野良猫のインスタンスを生成するということ。













クラスを定義することによって、インスタンスを生成できるようになる
さらに、定義したクラスの変数を利用できるようになる。
(この変数を、クラス型変数という)


package neighborhood;

public class main {

 public static void main(String[] args) {

  // 野良猫を生成(インスタンスを生成)
  // StrayCatクラスから インスタンスを生成して、変数 c に代入
  StrayCat c = new StrayCat();
 }

}

この場合、
StrayCatクラスから、インスタンスを生成して
生成したインスタンスをStrayCat型の変数 c を宣言、代入している。

(定義されたクラスの分だけ、利用できる型が増えていく!)


次に、② 野良猫に、空腹度を設定する
これは、StrayCatクラスが持っている属性(フィールド)を利用して、値を代入すること。












newなどはいらないので、簡単。


package neighborhood;

public class main {

 public static void main(String[] args) {

  // 野良猫を生成(インスタンスを生成)
  // StrayCatクラスから インスタンスを生成して、変数 c に代入
  StrayCat c = new StrayCat();

  // 野良猫フィールドの空腹度に初期値をセットする

  c.hungry = 10;

  System.out.println(c.name + "の空腹度は" + c.hungry + "です");
 }

}








最後、③ 野良猫に、「ねだる」、「食べる」、「逃げる」指示を出す
これは、インスタンスのメソッドの呼び出し。













package neighborhood;

public class main {

 public static void main(String[] args) {

  // 野良猫を生成(インスタンスを生成)
  // StrayCatクラスから インスタンスを生成して、変数 c に代入
  StrayCat c = new StrayCat();

  // 野良猫フィールドの空腹度に初期値をセットする

  c.hungry = 10;

  System.out.println(c.name + "の空腹度は" + c.hungry + "です");

  // インスタンスのメソッドを呼び出す

  c.cadge();
  c.eat();
  c.escape();
 }

}











これで3ステップは完了です!!!

ただ、これだと、物足りないので、時間をみて、改良します。