メンバー変数(フィールド)

Revised: Dec./23rd/2003: Since: Dec./26th/2001

メンバー変数とは何か

クラスのメンバーとして考えられる変数であるメンバー変数についてまとめておきます。クラスの特性として参照可能な変数やメソッドは、そのクラスのメンバーと呼ばれます。

メンバ変数は、オブジェクトの状態を表す属性を保持するためのフィールドです。また、修飾子 static を指定されていないメンバ変数は、インスタンス毎に確保される変数となり、インスタンス変数とも呼ばれます。

メンバー変数は、クラスの中、且つメソッドの外側に記述します。メンバー変数は、当該クラス内の任意のメソッドから参照可能です。また、他のクラスから生成されたオブジェクトからもアクセス可能です。

次のクラスは、メンバー変数を持ち、当該クラス内の複数のメソッド及び、他のクラスから利用している例です。

AccountDemo.java

class Account {
	// メンバー変数
	int balance;
	
	void setBalance(int aBalance) {
		// 自分のクラスのメンバー変数へのアクセス
		balance = aBalance;
	}
	int getBalance() {
		// 自分のクラスのメンバー変数へのアクセス
		return balance;
	}
}
class AccountManager {
	void transfer(Account account, int ammount) {
		// オブジェクトのメンバー変数へのアクセス
		account.balance += ammount;
	}
}
class AccountDemo {
	public static void main(String[] args) {
		// オブジェクトの生成
		Account obj = new Account();
		// オブジェクトのメソッドの利用
		obj.setBalance(1000);
		System.out.println(obj.getBalance());
		// オブジェクトの生成
		AccountManager obj2 = new AccountManager();
		// オブジェクトのメソッドの利用
		obj2.transfer(obj, 100);
		System.out.println(obj.getBalance());
	}
}

実行結果:

C:\java>javac AccountDemo.java
C:\java>java AccountDemo
1000
1100
C:\java>

ローカル変数とメンバー変数の違い

メソッド内やメソッド引数で定義される変数の有効範囲(スコープ)は、当該メソッド内にしか及びません。更に、メソッド内のブロック内部で定義された場合は、そのブロック内から制御が外れるとメモリ上からドロップされて永遠に失われます。このような変数をローカル変数と呼びます。ローカル変数は制御がそのスコープから外れるとメモリ上からドロップされる変数です。

一方、メンバ変数の場合は、そのクラスのオブジェクトへの参照が存在する限り、メモリ上に保持されます。メンバ変数は、オブジェクトとともに持続し続ける変数です。

スコープについては後で特別に説明します。

メンバー変数の修飾子

フィールドは異なるクラスからもアクセスできるのですが、そのアクセス制限を修飾子で実現できます。

変数の修飾子
final 初期化した値以外に変更できない。定数として用いる。
private 同じクラスからしかアクセスできない。他のクラスから利用したければ、当該クラスのメソッドを介する。
省略 同じパッケージ内からしかアクセスできない。 final, static 宣言とは共存できる。
protected 同じパッケージ、またはそのサブクラスからしかアクセスできない。
public アクセスに制限がない。
static 静的変数。通常の変数は、インスタンスごとに異なる値を保持し、インスタンス変数と呼ばれる。一方、静的変数はインスタンスによらず共通のメモリ領域を占有する。クラスAをインスタンス化したインスタンス1とインスタンス2があるときに、インスタンス1が静的変数を10にセットしたら、インスタンス2から参照しても10になっている。静的変数の利用にはインスタンス化の必要がない。

private, protected, public 修飾子はアクセス制限の宣言ですから、相互に排他的です。即ち、 privatepublic を同時に宣言するとコンパイルエラーになります。この三つを何れも宣言しない場合は同じパッケージ内からしかアクセスできないと解釈されます。

データの保護とカプセル化という観点では、フィールド xxxpublic を指定したい場合、フィールド自身は private 宣言しておき、他のクラスからのアクセスに備えて、フィールドアクセス用のメソッド getXxx(), setXxx()public 宣言する方が望ましいとされます。このようなメソッドを、 getter/setter と呼び、合わせて accessor と呼びます。

class FieldDemo {
	// メンバー変数
	private String name;
	
	// セッター・メソッド
	public setName(String aName) {
		name = aName;
	}
	// ゲッター・メソッド
	public getName() {
		return name;
	}
}

原則として、全てのメンバー変数は private にして、public なメソッドでアクセスするようにします。メソッドでもできる限りprivateにしておき、必要最小限のメソッドだけをpublic修飾子を指定して公開します。

変数の有効範囲(スコープ)については、あとの節で説明します

アクセス修飾子については、あとの節で説明します

メンバ変数の初期化

ローカル変数と同様に、メンバー変数も明示的に初期化できます。

class Initialization {
	private int score = 50;
	
	public void modScore(int ammount) {
		score += ammount;
	}
	public int getScore() {
		return score;
	}
}
class InitializationDemo {
	public static void main(String[] args) {
		Initialization obj = new Initialization();
		obj.modScore(-15);
		System.out.println(obj.getScore());
	}
}
C:\java>javac InitializationDemo.java
C:\java>java InitializationDemo
35

メソッド内で定義される変数(ローカル変数)は、明示的に初期値を代入しておかないと利用できません。

これに対して、メンバ変数の場合は明示的に初期化しなくても、暗示的に初期値が代入されます。但し、実際はどこかで明示的に初期化しておくものです。

メンバ変数の暗示的な初期値
整数0
浮動小数点数0.0
char'\u0000' (空文字)
booleanfalse
参照型null

基本的に初期値は「空」だと思えば良いでしょう。

TestMember.java:

class TestMember {
	//メンバ変数
	private static int i;
	private static double d;
	private static char c;
	private static boolean b;
	private static String a[] = new String[3];
	public static void main(String[] args) {
		System.out.println("    int: "+i);
		System.out.println(" double: "+d);
		System.out.println("   char: "+c);
		System.out.println("boolean: "+b);
		System.out.println(" 参照型: "+a[0]+", "+a[1]+", "+a[2]);
	}
}

main() メソッドでインスタンス化しないでメンバ変数を利用しますので、メンバ変数を静的変数として static 宣言しておきます。

ここで宣言されたメンバ変数は何れも初期化されていないので、暗示的に代入された初期値が出力されるはずです。

C:\Java>javac TestMember.java
C:\Java>java TestMember
    int: 0
 double: 0.0
   char:
boolean: false
 参照型: null, null, null

それぞれの基本データ型に対する初期値が出力されています。



Copyright © 2001, 2003 SUGAI, Manabu. All Rights Reserved.
SEO [PR] !uO z[y[WJ Cu