オブジェクト変数はnew演算子を使えば1つのクラスから複数のオブジェクトを生成してクラスの中のフィールド変数やメソッドに別の動きをさせることができます。これこそオブジェクト指向の醍醐味の1つかもしれません。
しかし生成されたばかりオブジェクトのフィールド変数の初期値は
数値型:0
文字型:空文字
boolean型:false
もしくはコンパイル時に記述した初期値が設定されますが、たくさんのオブジェクトをつかうなら初期値の定義は個々によって変化するはずです。
コンストラクターはインスタンス生成時にフィールド変数に値を設定する役割がありクラスオブジェクト生成に必須のきのうです。
■コンストラクターの記述
ではどこに記述するかというと前々回からオブジェクト生成のときにあえてなにも触れませんでしたが、
MainClass mc = new MainClass(); ← このメソッドのようなものがコンストラクターです
実際にクラス内には
public class MainClass {
public MainClass() {
/*コンストラクター内で行う処理*/
}
}
一見メソッドの一種にも見えますが返却値型が記述されません。
コンストラクターでの処理は一般的にフィールド変数に値を設定することとオブジェクト指向設計でいうところの集約とコンポジットの実現ぐらいしか記述しないのですがこのコンストラクターがないとクラスを使用することが出来ません!!
ですが今まで紹介してきたプログラムには定義していないのにちゃんとうごいていました。これは「デフォルトコンストラクター」と呼ばれる何もしないコンストラクターをコンパイラーが勝手に生成してくれるためです。
個人的見解としてコンストラクターを最も使うのはJava API であらかじめ定義されているクラスを利用する時です(BuffererdReader や DecimalFormatなど。)
つまりコンストラクターは必ず必要な手続きだがなくても困らないといったあいまいな手続きなのです。
コンストラクターはオーバーロードを使ってたくさん用意できるためデータの使用パターンを決めることでString型フィールド値にNULLが入る(文字列の初期値はStringクラスを利用しているので初期設定していないと必ず参照情報ナシを表すNULLが入る)事を防げる。
■コンストラクターをつかったプログラムの例
public class MainClass {
int num;
String name;
int age;
public MainClass() {
/*コンストラクター内で行う処理*/
this.num = 0;
this.name = "no name";
this.age = 20;
}
public MainClass(int num , String name , int age){
this.num = num;
this.name = name;
this.age = age;
}
public void show(){ System.out.println( num + name + age); }
}
main() {
/*一部省略*/
MainClass mc = new MainClass();
mc.show();
mc = new MainClass(10,"man",45);
mc.show();
}
_____________________
実行結果
--------------
0 no name 20
10 man 45
---------------
コンストラクターの記述中心にプログラムをつくったのでmainメソッドは大部省略しています
mcオブジェクトではshow()を2回呼び出していますがnew演算子のおかげで別のものとして判定してます。
コンストラクター内でつかっている「this」は「このクラス」という意味があり「this.name」は引数のnameを呼び出しているわけではなくフィールド変数を呼び出しているということです。コンストラクターはただた代入するだけのために引数をつかうのでthisをつかって同じ名前の変数を使えるようにすることは役割の明示化にもできるのでこれから良くつかうと思います
最後にアクセス修飾子(ここではpublic)ですがコンストラクタは常に他のクラスから呼び出されるためだけにあるので「public」、「なし」の2つだけです。
■クラス配列
2次元配列の回でExcelのような表形式でデータ管理するためには2次元配列を使うしかないと言いましたが2次元配列の弱点は列ごとにデータ型を指定出来ない。(同じ型の変数をたくさんつくっているだけなので)
成績表のような表に各点数だけでなく氏名もデータとして管理する場合データごとに配列つくれば解決するが表らしさ(条件に合うデータの検索機能)にやや不備がある。
こういうときは クラス型の配列(オブジェクト変数を複数まとめて管理)をつかうことで表らしさを保てる。
■宣言とインスタンス(ここでは上記にあるMainClassクラスを使用して説明する)
/*初期値付き*/
MainClass [] mc = { new MainClass(1,"加藤",15), new MainClass(2,"鬼藤",30),new MainClass(3,"工藤",100),
new MainClass(4,"近藤",80),new MainClass(5,"佐藤",5)};
/*とりあえず領域確保*/
MainClass [ ] mc = new MainClass [5];
どちらも普通の配列と同じ記述で宣言しますが上の場合は5つ全部がオブジェクト生成した段階での配列だから問題なしですが
下の場合インスタンス化がされてないためこのあとに各要素をインスタンス化しないとコンパイルエラーは起きませんが実行中に「NullPointerException」の例外処理が発生してしまいます(catchがうまく動作しないので例外処理としての想定は出来ない)
つまりコンストラクタの値をループ上で入力しながらインスタンス化ですべての配列に入力されなかった場合、生成された要素数もチェックしなければならない
使用例: mc[0].show();
同様に動的配列でも同じことが出来るためArrayListやVecter型を独自クラスすればさらにExcelに近づけることが可能
最近実行結果やソースコードの画像をアップロードすると文字がつぶれてよくわからないため(クリックして拡大すればOK)
ソースコードを文章としてのせていますが
オブジェクト指向をたくさん使えば使うほど1行のコードが長い(とくにクラス宣言やMainメソッド)ため次のように省略
メインメソッド ⇒ main(){ }
入力フォーマット ⇒ br (インスタンス化をすでにされているとする)
アクセス修飾子 ⇒ どの修飾子でも動作が変わらなければ記述ナシ
出力 ⇒ Sysout();
実行結果 ⇒今回のような形式とあまり変化がない形式で表記するが毎回変わるかも?