参照型変数をフィールドに持つ
質問:参照型変数をフィールドに持つことはできますか?
解答:もちろんできます。
フィールドには普通の変数はもちろん、参照型変数を持つこともできます。
逆に言うと、参照型変数を持たせたとしても、一般的な参照型変数と違いはないというところを覚えておいた方がいいでしょう。
/**
* 自クラスの参照型変数をフィールドとして持つクラス。
*/
class RefField
{
// 自クラスの参照型変数のフィールドdataを定義します。
RefField refField;
// int型変数のフィールドdataを定義します。
int data;
}
/**
* 実行用クラス。このクラスを実行してください。
*/
class RefFieldRunner
{
public static void main( String[] args )
{
// まずRefFieldクラスのインスタンスを作り、
// 参照型変数refに参照を入れます。
RefField ref = new RefField();
// もうひとつRefFieldクラスのインスタンスを作り、
// 先ほど作ったインスタンスのrefFieldフィールドに
// 参照を入れます。
ref.refField = new RefField();
// 2つめのインスタンスにあるdataフィールドに
// 「100」を入れ、それを出力します。
ref.refField.data = 100;
System.out.println( ref.refField.data );
// 実行結果:
// 100
}
}
// RefFieldRunner.java /** * 自クラスの参照型変数をフィールドとして持つクラス。 */ class RefField { // 自クラスの参照型変数のフィールドdataを定義します。 RefField refField; // int型変数のフィールドdataを定義します。 int data; } /** * 実行用クラス。このクラスを実行してください。 */ class RefFieldRunner { public static void main( String[] args ) { // まずRefFieldクラスのインスタンスを作り、 // 参照型変数refに参照を入れます。 RefField ref = new RefField(); // もうひとつRefFieldクラスのインスタンスを作り、 // 先ほど作ったインスタンスのrefFieldフィールドに // 参照を入れます。 ref.refField = new RefField(); // 2つめのインスタンスにあるdataフィールドに // 「100」を入れ、それを出力します。 ref.refField.data = 100; System.out.println( ref.refField.data ); // 実行結果: // 100 } }
このプログラムのRefFieldクラスは、自分自身のクラスの参照型変数をフィールドとして持っています。
* 自クラスの参照型変数をフィールドとして持つクラス。
*/
class RefField
{
// 自クラスの参照型変数のフィールドdataを定義します。
RefField refField;
// int型変数のフィールドdataを定義します。
int data;
}
/** * 自クラスの参照型変数をフィールドとして持つクラス。 */ class RefField { // 自クラスの参照型変数のフィールドdataを定義します。 RefField refField; // int型変数のフィールドdataを定義します。 int data; }
ここで注意して欲しいのは、自クラスの参照型変数だからといって、インスタンス自身への参照を持つわけではないということです。
自クラスのフィールドなので「自分自身が入る」ように感じるかもしれませんが、クラスとインスタンスは別です。自クラスの参照型変数でも、その変数にどのインスタンスの参照を入れても構わないわけです。
というわけで、この例では2つインスタンスを作って、一方のrefFieldフィールドにもう一方の参照を入れています。
// 参照型変数refに参照を入れます。
RefField ref = new RefField();
// もうひとつRefFieldクラスのインスタンスを作り、
// 先ほど作ったインスタンスのrefFieldフィールドに
// 参照を入れます。
ref.refField = new RefField();
// まずRefFieldクラスのインスタンスを作り、 // 参照型変数refに参照を入れます。 RefField ref = new RefField(); // もうひとつRefFieldクラスのインスタンスを作り、 // 先ほど作ったインスタンスのrefFieldフィールドに // 参照を入れます。 ref.refField = new RefField();
このようにすることで、インスタンスとインスタンスが継ながったような感じになります。
2つインスタンスを作って、片方のフィールドからもう片方へ継ながっているわけです。
refFieldフィールドは「フィールド」なので混乱するかもしれませんが、していることは普通の変数と同じ、つまりref変数と同じです。フィールドということに騙されず、単純に考えましょう。
最後に、2つめのインスタンス内のdataフィールドに数値を入れます。
// 「100」を入れ、それを出力します。
ref.refField.data = 100;
System.out.println( ref.refField.data );
// 実行結果:
// 100
// 2つめのインスタンスにあるdataフィールドに // 「100」を入れ、それを出力します。 ref.refField.data = 100; System.out.println( ref.refField.data ); // 実行結果: // 100
「.」が2つもあって分かりづらいかもしれませんが、左からひとつずつ考えていけば大丈夫です。
「ref.refField.data」の「ref」には「1つめのインスタンスへの参照」が入っていますから、これは「1つめのインスタンス内のrefField.data」と置き換えられます。
次に「1つめのインスタンス内のrefField.data」の「1つめのインスタンス内のrefField」には「2つめのインスタンスへの参照」が入っていますから、これは「2つめのインスタンス内のdata」と置き換えられます。
「2つめのインスタンス内のdata」とはつまり「2つめのインスタンス内のdataフィールド」ということなので、「data = 100」となり、dataフィールドに100を入れることになります。
「.」がいっぱいついたり、参照型変数がフィールドになっていて分かりづらいように感じるかもしれませんが、でも単純に「参照型変数に入っている参照がインスタンスに結びついている」だけで、これまでの例と違いはありません。
難しく考えず、ひとつひとつ分解して考えて、それをイメージできるようにしましょう。
「イメージ」を忘れずに
この章では、クラスとインスタンス、参照の関係について嫌というほど見てきました。
ここまで何度となく似た図を見たことで、頭の中にこれらの関係がイメージできるようになったと思います。
そのイメージが大事です!
なんとなくクラスを使うのではなく、頭の中でクラス・インスタンス・参照の関係が思い浮かぶようになることで、ちゃんとクラスというものを理解できるようになり、応用が利くようになるからです。
このイメージを大切に、いつでも思い浮かべられるようにしましょう。