第2章 クラスの基本
2.4 参照型について
これまで学習してきた範囲で既に参照型について扱ってきています。まずは配列、文字列を扱う「String型」、本章で習ってきた「クラス型」があります。では参照型とは具体的にどのようなものか詳しく説明していきます。
2.4.1 基本データ型と参照型
Javaプログラミングでは数値や文字が入った変数は「基本データ型」と呼ばれ、配列やオブジェクトの場所情報が入った変数は「参照型」と呼ばれます。簡単にまとめると以下のようになります。
図 2.4.1: 基本データ型と参照型の分類
図 2.4.2: 基本データ型へデータ代入
図2.4.2のように「int型変数num」に「数値10」を代入します。そうすると変数numという箱の中にデータが入ったイメージになります。基本データ型はこのような変数(箱)内部の、データを直接やり取りするものになります。では続いて参照型はどのようなイメージになるかクラス型で説明していきます。
参照型(配列型,クラス型等)
これまでComputer型のオブジェクトを生成するために、以下のような代入文を記述してきました。
Computer com; com = new Computer(); // または Computer com = new Computer();
この代入文は右辺においてnew演算子がオブジェクトを生成して、それが左辺の変数comに代入されるように思えますが実際はそうではありません。
図 2.4.3: クラス型変数の間違い代入イメージ
実際の動作としてnew演算子はオブジェクトを作成しメモリ領域内に格納します。そしてnew演算子の結果はオブジェクト実体の場所情報と呼ばれる特殊な値を返します。その結果、クラス型の変数にはそのオブジェクト参照情報を代入にすることになります。このオブジェクト実体の場所情報からアクセスするものを参照型と呼びます。
図 2.4.4: クラス型変数の正しい代入イメージ
オブジェクト実体の場所情報を扱う型をクラス型といい、クラス型、配列型、そして12章で学習するインターフェース型をまとめて参照型といいます。参照型はオブジェクト実体の場所情報を使ってアクセスする型の総称です。これらの型の変数を一般的にオブジェクト変数といいます。オブジェクト変数はオブジェクト実体の場所情報を格納できる変数という意味になります。
次の項でオブジェクト変数の初期化パターンについて紹介していきます。
2.4.2 オブジェクト変数の初期化について
クラスの型でオブジェクト変数を宣言したときに代入できる初期値のパターンについて説明します。
2.2.1で利用した「Computer」クラスを例に説明を行います。
Computer com = new Computer();
上記のように基本はオブジェクト変数を宣言すると同時に、new演算子でオブジェクトを生成します。そのオブジェクト実体の場所情報がオブジェクト変数comの値として格納されます。今までのプログラムでは、オブジェクト変数の宣言時にオブジェクト実体の場所情報を格納していましたが、その他のパターンについても紹介します。オブジェクト変数の宣言時に行える処理としては以下の4パターンがあります。
1. 「オブジェクト実体の場所情報」
new演算子を実行したときに受け取る値
2. 「何もなし」
クラス型のオブジェクト変数宣言のみ
3. 「null」
有効でない場所情報
4. 「生成済みのオブジェクト実体の場所情報」
別のオブジェクト実体の場所情報を代入
2.4.3 オブジェクト変数の初期化を行わないプログラム
クラス型のオブジェクト変数の宣言のみ行い、そのオブジェクトのメンバにアクセスを行います。
オブジェクト変数の初期化を行わない場合、どのような動作をするか学習しましょう。
① ソース・フォルダー: myproj_basic/src
② パッケージ: jp.co.f1.basic.ch02
③ 名前: NoInitializationObjectVariable
④ 作成するメソッド・スタブの選択: public static void main(String[] args) にチェックを入れる
package jp.co.f1.basic.ch02; class Computer6 { String os; int memory; // フィールド変数の値を表示するメソッド public void show() { System.out.println("OSは「" + os + "」です。"); System.out.println("メモリサイズは「" + memory + "MByte」です。"); } } public class NoInitializationObjectVariable { public static void main(String[] args) { // Computer6型のオブジェクト変数comを定義 Computer6 com; // showメソッドにアクセス com.show(); } }
実行結果
※実行はできずにEclipseではコンパイルエラーとなる。
Eclipseのソースファイル画面
※20行目の左側にエラーのマークが出ています。
解説
17行目でComputer6クラス型のオブジェクト変数を宣言しただけでは、変数の中身は空っぽで何も入っていないことに注意してください。「オブジェクト実体の場所情報」が入っていないことを「初期化されていない」といいます。
Computer6 com;
20行目のように初期化されていないオブジェクト変数に「.(ドット)」を用いてメンバヘアクセスすると実行結果のようにコンパイルエラーになるので注意して下さい。
com.show();
ポイント
- 初期化されていないオブジェクト変数に対して、メンバアクセスを行うとコンパイルエラーになる。
続いてオブジェクト変数を「null」で初期化した場合のサンプルを紹介します。
2.4.4 オブジェクト変数をnullで初期化するプログラム
クラス型のオブジェクト変数にnullを代入して、そのオブジェクトのメンバにアクセスをいます。
初期化を行わない場合との違いや、nullとはどのような意味があるのかについて学習しましょう。
① ソース・フォルダー: myproj_basic/src
② パッケージ: jp.co.f1.basic.ch02
③ 名前: NullInitializationObjectVariable
④ 作成するメソッド・スタブの選択: public static void main(String[] args) にチェックを入れる
package jp.co.f1.basic.ch02; class Computer7 { String os; int memory; // フィールド変数の値を表示するメソッド public void show() { System.out.println("OSは「" + os + "」です。"); System.out.println("メモリサイズは「" + memory + "MByte」です。"); } } public class NullInitializationObjectVariable { public static void main(String[] args) { // Computer7型のオブジェクト変数comを定義しnull値で初期化 Computer7 com = null; // showメソッドにアクセス com.show(); } }
実行結果
※2.4.3のサンプルと違い実行はできるが、実際に実行するとエラーが出てしまう
上記画面結果に出ている「java.lang.NullPointerException」のことを例外と呼びます。
Javaプログラミングにはこのような例外が発生した場合、プログラムを中断させずに処理を続行できる仕組みが用意されています。
例外を処理する方法については8章で詳しく説明しますので、本章では例外を処理する仕組みがJavaプログラミングにはあることを覚えておいて下さい。
Eclipse上でのソースファイル結果
※20行目の左側に警告が出ている。
解説
17行目でオブジェクト変数に初期値としてnull値を代入しています。
Computer7 com = null;
nullとは「有効ではない場所情報」です。場所情報の一種ですが、どんなオブジェクトも参照していない無効な参照情報であることを示す値となっています。
整数型の変数を「0」で初期化するように、nullは参照型変数のデフォルト値として初期化に使われる事があります。
続いて20行目でメンバのshowメソッドにアクセスしています。
com.show();
ソースファイルの結果を見てもらって分かるように2.4.3のサンプルとは違い、コンパイルエラーではなく警告になっている点です。nullは参照情報の一種のためオブジェクト変数に代入すると、その変数は初期化されているとみなされます。コンパイラはnullとそれ以外の場所情報を区別しないので、メンバにアクセスする式を記述してもコンパイルエラーになりません。結果、エラーが発生するのはプログラムを実行した時になります。変数comの中には「null」が入っており、実在するはずのオブジェクトを参照できずに20行目で実行時例外が発生します。
ポイント
- オブジェクト変数にnullを代入すると初期値とみなされるが、実行時にアクセスするとエラーになってしまう。
2.4.5 オブジェクト変数を別のオブジェクト変数で初期化(代入)するプログラム
クラス型のオブジェクト変数に別のオブジェクト変数を代入して、そのオブジェクトのメンバにアクセスをいます。
オブジェクト変数に別のオブジェクト変数を代入した場合、どのような動きをするか確認しましょう。
① ソース・フォルダー: myproj_basic/src
② パッケージ: jp.co.f1.basic.ch02
③ 名前: ObjectInitializationObjectVariable
④ 作成するメソッド・スタブの選択: public static void main(String[] args) にチェックを入れる
package jp.co.f1.basic.ch02; class Computer8 { String os; int memory; // フィールド変数の値を表示するメソッド public void show() { System.out.println("OSは「" + os + "」です。"); System.out.println("メモリサイズは「" + memory + "MByte」です。"); } } public class ObjectInitializationObjectVariable { public static void main(String[] args) { // Computer8型のオブジェクト変数com1を宣言とオブジェクトの生成 Computer8 com1 = new Computer8(); // com1オブジェクトの各値を設定 com1.os = "WindowsXP"; com1.memory = 2048; // Computer8型のオブジェクト変数com2を宣言と同時に別変数で初期化 Computer8 com2 = com1; System.out.println("com2にcom1を代入しました。\n"); // com1のshowメソッドにアクセス System.out.print("com1のさすパソコンの"); com1.show(); // com2のshowメソッドにアクセス System.out.print("com2のさすパソコンの"); com2.show(); } }実行結果
解説
17行目でComputer8オブジェクトを作成しています。19、20行目でフィールド変数osとmemoryに各値を代入しています。
Computer8 com1 = new Computer8(); com1.os = "WindowsXP"; com1.memory = 2048;
23行目でオブジェクト変数com2の宣言と同時に、既に宣言済みの変数com1の値で初期化を行っています。
Computer8 com2 = com1;
23行目処理をイメージで表現すると、以下の図2.4.5のようになります。このようなイメージと似たものをどこかで見た覚えはないでしょうか。入門テキストの第9章で学習した配列変数同士の代入でも、同じ配列情報を指し示すことになりました。クラス型も配列と同じ参照型の為、変数同士の代入を行うとその場所情報をコピーすることになります。結果としてオブジェクト変数同士の代入も、同じオブジェクトを指し示すようになります。
図 2.4.5: オブジェクト変数同士の代入
28、32行目ではオブジェクト実体の場所情報からshow()メソッドを呼び出してパソコン情報を表示しています
com1.show(); com2.show();
ポイント
- オブジェクト変数には既に作成済みのオブジェクト変数を代入できるが、オブジェクト実体は同じものを参照する事になる