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 修飾子はアクセス制限の宣言ですから、相互に排他的です。即ち、 private と public を同時に宣言するとコンパイルエラーになります。この三つを何れも宣言しない場合は同じパッケージ内からしかアクセスできないと解釈されます。
データの保護とカプセル化という観点では、フィールド xxx に public を指定したい場合、フィールド自身は 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' (空文字) |
boolean 型 | false |
| 参照型 | 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
それぞれの基本データ型に対する初期値が出力されています。