Javaではクラスという設計図(または型)を作成し、そのクラス内にはフィールドとメソッド等の部品を作成します。
しかし、その部品は基本的にインスタンスを作成しないと利用できません。今回はそのインスタンスを代入する変数やnullについての解説を行います。
もくじ
変数とインスタンス
変数は大別して、基本データ型とそれ以外の型に分かれます。
基本データ型は文法で用意されている型で8種類(char、byte、short、int、long、float、double、boolean)あります。
基本データ型以外の型の多くはクラスです。クラスという型はプログラマーが作成できる型という位置づけになります。
型は設計図のようなもので、基本データ型はどんな種類のデータを代入できるかが型によって決まります。一方、クラス(型)はクラスが持っている設計図のフィールド※やメソッドが利用できるかが決まります。
※フィールドはほとんどprivate宣言されている為、外部からは利用できないのでメソッド経由でフィールドは利用します
つまり、基本データ型は利用できるデータの種類、クラスは利用できるフィールドとメソッドの種類が決まるということになります。
クラスとインスタンスの記述や概念をもう一度記載します。
インスタンス変数(復習)
クラス内のフィールドやメソッドは基本的にインスタンスを生成して利用します。つまり、以下のような宣言だけの記述ではフィールドやメソッドは利用できません。クラスを型に持つ変数はインスタンス変数と呼ばれます。
インスタンス変数の宣言 | クラス名 インスタンス変数名 ; |
---|---|
記述例 | Taiyaki taiyaki_anko ; |
フィールドやメソッドを利用したい場合は、上記で作成したインスタンス変数内にインスタンスを生成し代入します。インスタンスを生成際には「new クラス名()」と記述します。
インスタンスの生成 | インスタンス変数名 = new クラス名() ; |
---|---|
記述例 | taiyaki_anko = new クラス名() ; |
また、インスタンス変数の宣言と、インスタンス生成は1行にまとめることも可能です。
インスタンスの生成 | クラス名 インスタンス変数名 = new クラス名() ; |
---|---|
記述例 | Taiyaki taiyaki_anko = new Taiyaki() ; |
インスタンス変数と参照値
インスタンス変数は基本データ型の変数同様、初期化しなければエラーとなります。
以下のようなプログラムを作成してみましょう。
インスタンスと変数 サンプルプログラム
以下のプログラムを「Number30.java」という名前でworkフォルダ内に保存します。
保存が完了したら、コマンドプロンプトを起動し、コンパイルおよび実行を行ってみましょう。※Taiyaki.javaは作成済みとしてNumber30.javaは記述されています。(Taiyaki.javaの記述)
1 2 3 4 5 6 |
class Number30{ public static void main(String[] args){ Taiyaki taiyaki_anko = new Taiyaki(); System.out.println(taiyaki_anko); } } |
実行例
C:\work>javac Number30.java
C:\work>java Number30
Taiyaki@15db9742
※実行例はコンパイルおよび実行までの例を表示しています。
以下はNumber30.javaの記述をイメージ図にしたものです。
インスタンス生成後、変数に代入するのはインスタンスの実体ではなく参照値となります。
Taiyaki taiyaki_anko = new Taiyaki() ;
インスタンス変数を利用する際の注意点
基本データ型同士を代入すると値のコピーとなります。以下は基本データ型同士の代入です。
1 2 3 4 5 6 7 8 |
int a = 200 ; int b = a ; //値のコピー System.out.println(a); //200 System.out.println(b); //200 b = 100 ; //bの値を変更 System.out.println(a); //200 System.out.println(b); //100 |
値をコピーするだけなので、aとbの値は別々の値として保存されます。つまり、aの値は変更されず、bの値だけ変更されます。
しかし、インスタンス変数は違います。
インスタンスと参照値 サンプルプログラム
「Number30.java」を以下のように編集し、上書き保存します。
保存が完了したら、コマンドプロンプトを起動し、コンパイルおよび実行を行ってみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Number30{ public static void main(String[] args){ Taiyaki taiyaki_anko = new Taiyaki(); System.out.println(taiyaki_anko); //追加 Taiyaki taiyaki_tyoko = taiyaki_anko; System.out.println(taiyaki_tyoko); taiyaki_anko.nakami = "あんこ"; taiyaki_tyoko.nakami = "チョコ"; taiyaki_anko.open(); taiyaki_tyoko.open(); } } |
実行例
C:\work>javac Number30.java
C:\work>java Number30
Taiyaki@15db9742
Taiyaki@15db9742
たい焼きの中身はチョコです
たい焼きの中身はチョコです
※実行例はコンパイルおよび実行までの例を表示しています。
インスタンス変数から別のインスタンス変数に代入を行うと参照値のコピーが行われます。
参照値が同一の場合、変数名は異なっても同一インスタンスを利用していることになります。
以下のように、「taiyaki_anko」内に”あんこ”を代入します。
taiyaki_anko.nakami = “あんこ”;
次に、「taiyaki_tyoko」内に”チョコ”を代入した場合
taiyaki_tyoko.nakami = “チョコ”;
変数名は別ですが利用しているインスタンスは同一のため、「taiyaki_anko」内も”チョコ”となっています。下記は両方とも同じ内容が表示されます。
taiyaki_anko.open();
taiyaki_tyoko.open();
インスタンスごとに別のデータを持たせたい場合は、インスタンス変数を代入するのではなく、インスタンスを生成して利用するようにしましょう。具体的には以下のように修正すると別インスタンスとなります。
//Taiyaki taiyaki_tyoko = taiyaki_anko;
Taiyaki taiyaki_tyoko = new Taiyaki();
参照値の補足
以下のように、インスタンス変数同士を比較すると参照値の比較となります。
参照値が同一であればtrue、異なればfalseとなります。
System.out.println(taiyaki_anko == taiyaki_tyoko);
インスタンス変数とnull
基本的にはインスタンスを生成しなければメソッドやフィールドを利用できません。しかし、プログラムを記述する際には、「インスタンスの生成は状況に応じて行う」といったパターンがあります。
※以下の説明はあくまでもnullが必要だと思われるパターンの一例です。
例えば、以下のようなパターンです。
1 2 3 4 5 |
Car car = new Car(); if(条件){ 条件に合致した時にcarを利用 } |
上記のプログラムだと、ifブロック内でのみインスタンス変数carを利用するのですが、条件に関係なくインスタンスを必ず生成しています。
プログラム自体のボリューム(作成するインスタンス)がすくなければ問題ありません。しかし、プログラムのボリューム(作成するインスタンス)が多なればなるほど、無駄なインスタンスをたくさん作らなければならない状況になってしまいます。
ちなみに、下記のようにif内で宣言する手もありますが、それだとifブロック終了後にインスタンス変数carが利用できなくなってしまいます。
1 2 3 4 5 6 7 8 |
if(条件){ Car car = new Car(); 条件に合致した時にcarを利用 } if(条件){ 条件に合致した時にcarを利用 } |
もし、インスタンス変数は用意はするが、生成は後回しにしたい場合等に登場するのが「null」です。nullは特別な値(リテラル)で、参照値がないことを示すものです。※噛み砕くとインスタンスや配列が利用できないことを示す値
以下のように、型がクラスや配列の場合にはnullが代入可能です。nullを代入することによって、状況に応じたインスタンス生成を行うことができるようになります。
1 2 3 4 5 6 7 8 9 10 |
Car car = null; if(条件){ car = new Car(); 条件に合致した時にcarを利用 } if(条件){ 条件に合致した時にcarを利用 } |
nullの補足
nullは値なので、if(car == null)のようなnullであるかどうかの比較も行えます。
nullの状態でメソッドやフィールドを利用すると実行時エラーが発生します。
(NullPointerExceptionというエラーです)
フィールドにクラスや配列の型で宣言を行うと、nullで初期化されます。
配列で利用する型がクラスや配列の場合、nullで初期化されます。
nullの状態でインスタンス変数を出力するとnullと表示されます。
nullの補足 サンプルプログラム
「Number30.java」を以下のように編集し、上書き保存します。
保存が完了したら、コマンドプロンプトを起動し、コンパイルおよび実行を行ってみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class Number30{ public static void main(String[] args){ Taiyaki taiyaki_anko = new Taiyaki(); System.out.println(taiyaki_anko); //Taiyaki taiyaki_tyoko = taiyaki_anko; Taiyaki taiyaki_tyoko = new Taiyaki(); System.out.println(taiyaki_tyoko); taiyaki_anko.nakami = "あんこ"; taiyaki_tyoko.nakami = "チョコ"; taiyaki_anko.open(); taiyaki_tyoko.open(); //追加 Taiyaki taiyaki_null = null; System.out.println(taiyaki_null == null); //null比較 System.out.println(taiyaki_null); //nullを出力 taiyaki_null.open(); //実行時エラー } } |
実行例
C:\work>javac Number30.java
C:\work>java Number30
Taiyaki@15db9742
Taiyaki@6d06d69c
たい焼きの中身はあんこです
たい焼きの中身はチョコです
true
null
Exception in thread “main” java.lang.NullPointerException
at Number30.main(Number30.java:20)
※実行例はコンパイルおよび実行までの例を表示しています。
参照値とnull 復習問題
- 以下の説明で正しいものを選んでください。
- 下のプログラムの実行結果として正しいものを選択肢の中から選んでください。
PC pc = new PC();
PC note_pc = new PC();
System.out.println(pc == note_pc); - 下のプログラムの実行結果として正しいものを選択肢の中から選んでください。
PC pc = new PC();
PC note_pc = null;
System.out.println(pc == note_pc); - 下のプログラムの実行結果として正しいものを選択肢の中から選んでください。
PC pc = null;
System.out.println(pc); - お疲れ様でした。
-
- 型に関係なく変数内には参照値が保存される
- Javaではインスタンス変数名で、インスタンスの実体が同じかどうか管理している
- インスタンス変数名が違っても、同じインスタンスを利用している場合がある
- ローカル変数でインスタンス変数を宣言した場合、new演算子を利用しなくても自動的に参照値が保存される
-
trueが表示される
falseが表示される
nullが表示される
- 参照値が表示される
-
trueが表示される
falseが表示される
nullが表示される
- 参照値が表示される
-
trueが表示される
falseが表示される
nullが表示される
- 参照値が表示される
まとめ
- インスタンス変数には参照値が保存されている
- インスタンス変数から別のインスタンス変数へ代入すると、参照値のコピーとなる
- nullは参照値がない(インスタンスが利用できない)ことを示す値
- フィールドは基本データ型以外を宣言すると、nullで初期化される
- 配列で利用する型が基本データ型以外の場合、nullで初期化される
- インスタンス変数を比較すると、参照値およびnullの比較ができる