■大域変数と局所変数■
変数の有効範囲(スコープ)とは
変数には,有効範囲(スコープ)が存在する.これは,次のような人物名でも同じ話である.
山田家の太郎君 田中家の太郎君
同じ太郎という名前なため,それぞれの家庭内では「太郎」君にお使いを頼むときには「太郎,買いものしてきて」と指示される.しかし,2人は別人であり,山田太郎君にお願いした仕事を,田中太郎君がしてくれるわけではない.
これは,Javaの変数でも同じである.
public class Example { public static void main(String[] args) { int y = 100; int x = square(3); //関数squareの呼出 } public static int square(int param) //関数squareの本体 { int y=param; y = y * y; return y; } }
この例では次のふたつの変数がたまたま同じ名前である.
main関数の中のint y funcA関数の中のint y
この2つの変数は,同じ名前であるがまったく別変数である.つまり,squareのyに値を代入しても,mainのyとは関係がなく,mainのyの内容が書き換わることはない.
これは,それぞれのyが宣言された関数の中だけで有効であることを意味し,そのことを有効範囲(スコープ)と呼ぶ.
有効範囲のルール
Javaにおける名前の有効範囲(スコープ)は,原則として次のルールに従う.
- 中括弧{}で括られたブロック中で宣言された変数などは,そのブロック内だけで有効
つまり,次のように関数内だけでなく,if文の中だけで有効な名前も存在する.
public static int square(int param) //関数squareの本体 { int y=param; //関数内で有効 if(y>0) { y = y * y; } else { int z=-1; //elseの中だけで有効な変数 y=z; } System.out.println(z); //←範囲外なのでここでエラー return y; }
その有効範囲のルールには,若干の例外がある.
- 仮引数は,関数の中で宣言された変数と同様に扱われる
- for文の()内で宣言された変数は,for文の繰り返し中だけで有効
2番めは次のようなもので,iとjは違う有効範囲を持った変数である.
for(int i=0; i<100; i++) { int j; }
有効範囲から出てしまった変数は消滅するため.変数jは,一度ループを繰り返すたびに消滅する.つまり一回前の繰り返しのときのjと,現在実行されている時のjは別の変数として扱われる.これに対し,iはfor文全体が終了するまでは消滅しない.次のwhile文でのiと同じ有効範囲を意味している.
{ //←while文全体を囲っているブロックが仮りに存在するとして考える int i; while(i) { int j; } }
大域変数
有効範囲(スコープ)を持った変数のことを局所変数(ローカル変数)と呼ぶ.それに対して有効範囲のない,プログラム内のどこでも有効な変数のことを大域変数(グローバル変数)と呼ぶ.
しかし,Javaでは大域変数は存在しない.すべての変数は局所変数である.有効範囲が一番大きな変数は,メンバ変数である.メンバ変数についてはオブジェクトの所で説明するが,メンバ変数の一種にクラス変数がある.
int xyz; //大域変数はJavaでは存在しないので,ここで文法エラー public class Example { static int abc=100; //クラス変数 public static void main(String[] args) { int y = 100; int x = square(abc); //関数squareの呼出 } public static int square(int param) //関数squareの本体 { int y=param; y = y * y + abc; return y; } }
一番上で宣言しようとしている変数xyzは,class宣言の外側にある.本来ならばここで宣言した変数は,すべての中括弧の外にあるので大域変数の意味を持つはずだが,Javaではこの位置で変数を宣言するとエラーにされる.
変数abcは,関数の外側かつclassの内側でstaticと宣言された変数である.これをクラス変数と呼ぶ.クラス変数の名前はクラスの内側全部で有効なため,関数mainと関数squareどちらでも読み書きすることができる変数となる.
クラス変数の利用
Javaでは,関数の返値はひとつしかreturnできない.複数の値を返したい場合には,クラス変数などのメンバ変数を介してそれに似た動作が書ける.例えば次のようにfuncを実行すると,クラス変数abcとdefに値を設定するようにしておけば,funcの2番めと3番めの返値のように使用することができる.
public class Example { static int abc=0; //クラス変数 static int def=0; //クラス変数 public static void main(String[] args) { int x = func(300); //xに返値300 int y = abc; //yに3000=300*10 int z = def; //zに30=300/10 } public static int func(int param) //関数squareの本体 { abc = param*10; def = param/10; return param; } }