| 目次| 1234567891011121314
| 資料| 予定| 課題| 宿題|

コマンドラインの引数

実はこれまで何回も出てきた main メソッドの引数は,String[ ] args とい う配列になっている(main メソッドの仕様は Java 言語で決まっているので 変更してはならない).String クラスは文字列を表す型なので,引数 args は文字列の型となる.main が呼び出されるとき,このプログラムに与えられ た引数が args に自動的に代入される.args の個数はargs.length で 得ることができるので,
  args[0] には 0 番目の引数
  args[1] には 1 番目の引数 
  args[2] には 2 番目の引数
         … … …
  args[args.length - 1] には最後の引数
  
が入ることになる.引数がない場合には,args.length の値は 0 になる. java を起動する時に
java プログラム名 a1 a2 .. an
のように後ろに空白で区切って文字列をいくつか書くと
args[0] <- "a1"
args[1] <- "a2"
..
args[n-1] <- "an"
のように配列argsの中に渡すことができる. BlueJ環境の場合,コマンドライン引数は,
 How to use BlueJ to start a main method with command-line arguments

If you are using BlueJ to build and test your programs, then please follow this 
procedure for starting a main method with command arguments:

 1. /Use the right mouse button to click/ on the class that holds the main
    method; a menu with several start-up options appears.
 2. Click on the void main; this causes a text field to appear.
 3. Type the command arguments in the text field. /For whatever reason, the
    arguments must be entered as a constant array of strings./

    For example, three arguments, a, 12, and -3.5, must be typed like this:

    {"a", "12", "-3.5"}

    Of course, a single argument, like 4, is entered like this:

    {"4"}

 4. Finally, start the main method. 
として利用する.

参照型変数の特徴

int型などの変数(基本型の変数)が値そのものを格納するハコを表していたの に対して,配列変数は値を格納するハコそのものではなく,値を格納するハコ が「コンピュータのメモリ(記憶装置)のどこに存在しているか」という配列の 「場所」を表しているものにすぎません.test1[0]でハコそのものを表します が,まず"test1"の部分でハコの集まりがどこにあるかを参照し,"[0]"の部分 でどのハコを対象にするかが決まります.このような種類の変数の事を基本型 の変数に対して参照型の変数と呼びます.参照型の変数には配列型変数のほか にクラス型の変数や(授業では扱いませんが)インターフェイス型の変数があり ます.

今回は,いくつかの例を通してこの特徴を具体的に説明します.

配列変数への代入

まず,先週説明したように普通に準備・確保・初期化した配列変数 test1 を test2 に代入する以下のプログラムを実行してみる.
public class Hairetsu1 {
    public static void main(String[] args) {
	// 配列変数の準備
	int[] test1;
	System.out.println("test1を宣言しました.");

	// 配列要素の確保
	test1 = new int[3];
	System.out.println("配列要素を確保しました.");

	//配列要素への代入
	test1[0] = 80 ;
	test1[1] = 60 ;
	test1[2] = 22 ;

	//配列変数(だけ)の用意
	int[] test2;
	System.out.println("test2を宣言しました.");

	//配列変数への代入
	test2 = test1;
	System.out.println("test2にtest1を代入しました.");
	
	for( int i=0; i<3 ; i++){
	    System.out.println("test1が指す "+(i+1)+
			       " 番目の人の点数は "+test1[i]+" です.");
	}
	    
	for( int i=0; i<3 ; i++){
	    System.out.println("test2が指す "+(i+1)+
			       " 番目の人の点数は "+test2[i]+" です.");
	}
	    
    }
}
実行結果
[onisi@m449 ~/Java] java Hairetsu1
test1を宣言しました.
配列要素を確保しました.
test2を宣言しました.
test2にtest1を代入しました.
test1が指す 1 番目の人の点数は 80 です.
test1が指す 2 番目の人の点数は 60 です.
test1が指す 3 番目の人の点数は 22 です.
test2が指す 1 番目の人の点数は 80 です.
test2が指す 2 番目の人の点数は 60 です.
test2が指す 3 番目の人の点数は 22 です.
実行結果を見ると配列そのものがコピーされたかのように見えるが,上のプロ グラム中で"new int[3]"を一回しか実行していないことからコンピュータが確 保した配列は実際には(int型の変数3個からなる)1個だけであり, "test1","test2"のどちらも実体は同じ配列を参照している.

このことを確認するため配列の要素を書き替えるプログラムを追加したものが 以下のプログラムである.

public class Hairetsu2 {
    public static void main(String[] args) {
	// 配列変数の準備
	int[] test1;
	System.out.println("test1を宣言しました.");

	// 配列要素の確保
	test1 = new int[3];
	System.out.println("配列要素を確保しました.");

	//配列要素への代入
	test1[0] = 80 ;
	test1[1] = 60 ;
	test1[2] = 22 ;

	//配列変数(だけ)の用意
	int[] test2;
	System.out.println("test2を宣言しました.");

	//配列変数への代入
	test2 = test1;
	System.out.println("test2にtest1を代入しました.");
	
	for( int i=0; i<3 ; i++){
	    System.out.println("test1が指す "+(i+1)+
			       " 番目の人の点数は "+test1[i]+" です.");
	}
	    
	for( int i=0; i<3 ; i++){
	    System.out.println("test2が指す "+(i+1)+
			       " 番目の人の点数は "+test2[i]+" です.");
	}

	test1[2] = 100;
	System.out.println("test1がさす 3 番目の人の点数を変更します.");
	
	for( int i=0; i<3 ; i++){
	    System.out.println("test1が指す "+(i+1)+
			       " 番目の人の点数は "+test1[i]+" です.");
	}
	    
	for( int i=0; i<3 ; i++){
	    System.out.println("test2が指す "+(i+1)+
			       " 番目の人の点数は "+test2[i]+" です.");
	}
    }
}
実行結果
[onisi@m449 ~/Java] java Hairetsu2
test1を宣言しました.
配列要素を確保しました.
test2を宣言しました.
test2にtest1を代入しました.
test1が指す 1 番目の人の点数は 80 です.
test1が指す 2 番目の人の点数は 60 です.
test1が指す 3 番目の人の点数は 22 です.
test2が指す 1 番目の人の点数は 80 です.
test2が指す 2 番目の人の点数は 60 です.
test2が指す 3 番目の人の点数は 22 です.
test1がさす 3 番目の人の点数を変更します.
test1が指す 1 番目の人の点数は 80 です.
test1が指す 2 番目の人の点数は 60 です.
test1が指す 3 番目の人の点数は 100 です.
test2が指す 1 番目の人の点数は 80 です.
test2が指す 2 番目の人の点数は 60 です.
test2が指す 3 番目の人の点数は 100 です.
追加したプログラムで "test1[2]"を100に変更したが,その内容の確認を行っ ている部分を見ると"test2[2]"も同じように変更されている.このことからも コンピュータが確保した配列は1個だけであり,"test1","test2"と見方が変わっ ているだけであることがわかる.

配列のコピー

それでは,中身も含めた配列のコピーをどのように扱うかであるが,以下の プログラムのように行う.
public class Hairetsu3 {
    public static void main(String[] args) {
	// 配列変数の準備
	int[] test1;
	System.out.println("test1を宣言しました.");

	// 配列要素の確保
	test1 = new int[3];
	System.out.println("test1の配列要素を確保しました.");

	//配列要素への代入
	test1[0] = 80 ;
	test1[1] = 60 ;
	test1[2] = 22 ;

	//配列変数test2の準備,配列要素の確保・初期化
	int[] test2 = { 0, 0, 0};
	System.out.println("test2を宣言・確保・初期化しました.");

	for( int i=0; i<3 ; i++){
	    System.out.println("test1が指す "+(i+1)+
			       " 番目の人の点数は "+test1[i]+" です.");
	}
	    
	for( int i=0; i<3 ; i++){
	    System.out.println("test2が指す "+(i+1)+
			       " 番目の人の点数は "+test2[i]+" です.");
	}

	// 配列 test1 のすべての要素を配列 test2 にコピー
	for( int i=0; i< 3 ; i++){
	    test2[i] = test1[i];
	}
	System.out.println("すべての要素を複写しました.");

	
	test1[2] = 100;
	System.out.println("test1がさす 3 番目の人の点数を変更します.");
	
	for( int i=0; i<3 ; i++){
	    System.out.println("test1が指す "+(i+1)+
			       " 番目の人の点数は "+test1[i]+" です.");
	}
	    
	for( int i=0; i<3 ; i++){
	    System.out.println("test2が指す "+(i+1)+
			       " 番目の人の点数は "+test2[i]+" です.");
	}
    }
}
実行例
[onisi@m449 ~/Java] java Hairetsu3
test1を宣言しました.
test1の配列要素を確保しました.
test2を宣言・確保・初期化しました.
test1が指す 1 番目の人の点数は 80 です.
test1が指す 2 番目の人の点数は 60 です.
test1が指す 3 番目の人の点数は 22 です.
test2が指す 1 番目の人の点数は 0 です.
test2が指す 2 番目の人の点数は 0 です.
test2が指す 3 番目の人の点数は 0 です.
すべての要素を複写しました.
test1がさす 3 番目の人の点数を変更します.
test1が指す 1 番目の人の点数は 80 です.
test1が指す 2 番目の人の点数は 60 です.
test1が指す 3 番目の人の点数は 100 です.
test2が指す 1 番目の人の点数は 80 です.
test2が指す 2 番目の人の点数は 60 です.
test2が指す 3 番目の人の点数は 22 です.
配列の複写後に"Hairetsu2"と同様に"test1[2]"の値を変更しているが "test2[2]"の値には変化はない."Hairetsu2"の場合と違って配列変数test2に ついてもその実体を
int[] test2 = { 0, 0, 0};
として確保し,
for( int i=0; i< 3 ; i++){
    test2[i] = test1[i];
}
とすることで要素1つ1つをコピーしている.

String型とStringBuffer型

String型とStringBuffer型

String型

String型はクラス型の1つであり(クラスについては次週を予定),配列型と同 じく参照型としての特徴を持っている.ただし,String型は中身の書き換えが できない型として定義されているので上の例ほどの違いはない.
public class String3 {
    public static void main(String[] args) {
	// String型変数の準備
	String test1;
	System.out.println("test1を宣言しました.");

	// 文字列の割り当て
 	test1 = new String("ABCDEFGHIJKLMN");
	System.out.println("test1に文字列 "+test1+" を割り当てました.");

	//String型変数test2の準備
	String test2 ;
	System.out.println("test2を宣言しました.");

	//String型変数への代入
	test2 = test1;
	System.out.println("test2にtest1を代入しました.");
	
	System.out.println("test1が指す文字列は "+test1+" です.");
	System.out.println("test2が指す文字列は "+test2+" です.");

	//test1から小文字変換したStringを作り置き換える.
	test1 = test1.toLowerCase();

	System.out.println("test1が指す文字列は "+test1+" です.");
	System.out.println("test2が指す文字列は "+test2+" です.");

	    
    }
}
実行例
[onisi@m449 ~/Java] java String3
test1を宣言しました.
test1に文字列 ABCDEFGHIJKLMN を割り当てました.
test2を宣言しました.
test2にtest1を代入しました.
test1が指す文字列は ABCDEFGHIJKLMN です.
test2が指す文字列は ABCDEFGHIJKLMN です.
test1が指す文字列は abcdefghijklmn です.
test2が指す文字列は ABCDEFGHIJKLMN です.
String型も参照型の1つなので,配列と同様に普通は宣言・確保・初期化が必 要である.上のプログラム中では,確保・初期化しない"test2"を用意し,"test1"で 確保した文字列同じ文字列を参照するようにしている.

実行結果を見ると"test1"の文字列が"test2"の文字列としてコピーされたかの ように見えるが,実際には少し異なる.はじめに確保された"ABCDEFGHIJKLMN" という"test2"が参照する文字列にはなにも変化は起きない.

	test1 = test1.toLowerCase();
と言う部分で"abcdefghijklmn"という新しい文字列が確保されてその文字列へ の参照がtest1に割り当てられている.

StringBuffer型

中身を書き替えられないString型に対して中身に対する変更(文字の追加・挿 入・置き換え)が可能なStringBuffer型と言うクラスが用意されている. StringBuffer型を使った以下の例を見てみる.
public class String1 {
    public static void main(String[] args) {
	// StringBuffer型変数の準備
	StringBuffer test1;
	System.out.println("test1を宣言しました.");

	// 文字列の割り当て
 	test1 = new StringBuffer("ABCDEFGHIJKLMN");
	System.out.println("test1に文字列 "+test1+" を割り当てました.");

	//StringBuffer型変数test2の準備
	StringBuffer test2 ;
	System.out.println("test2を宣言しました.");

	//StringBuffer型変数への代入
	test2 = test1; 
	System.out.println("test2にtest1を代入しました.");
	
	System.out.println("test1が指す文字列は "+test1+" です.");
	System.out.println("test2が指す文字列は "+test2+" です.");

	//test1を反転させる.
	test1.reverse();

	System.out.println("test1が指す文字列は "+test1+" です.");
	System.out.println("test2が指す文字列は "+test2+" です.");

	    
    }
}
実行例
[onisi@m449 ~/Java] java String1
test1を宣言しました.
test1に文字列 ABCDEFGHIJKLMN を割り当てました.
test2を宣言しました.
test2にtest1を代入しました.
test1が指す文字列は ABCDEFGHIJKLMN です.
test2が指す文字列は ABCDEFGHIJKLMN です.
test1が指す文字列は NMLKJIHGFEDCBA です.
test2が指す文字列は NMLKJIHGFEDCBA です.
実行例からもわかるように(この書き方の意味も次週を予定)
test1.reverse();
の部分で"test1"だけを反転させたつもりでも"test2"として参照すると同じよ うに反転してしまう.配列の場合の例"Hairetsu2"でも述べたように"new"を用 いて確保した文字列は1つだけであるため,"test1""test2"どちらで参照して もコンピュータの中で実際に参照される文字列は(反転した)同じものである.

以下のプログラム"String2"では,

 test2 = new StringBuffer(test1.toString()); 
の箇所で,StringBuffer型として確保した変数"test2"に"test1"が参照してい る内容と同じ文字列で新たに確保した文字列を割り当てている.
public class String2 {
    public static void main(String[] args) {
	// StringBuffer型変数の準備
	StringBuffer test1;
	System.out.println("test1を宣言しました.");

	// 文字列の割り当て
 	test1 = new StringBuffer("ABCDEFGHIJKLMN");
	System.out.println("test1に文字列 "+test1+" を割り当てました.");

	//StringBuffer型変数test2の準備
	StringBuffer test2 ;
	System.out.println("test2を宣言しました.");

	//StringBuffer型変数への代入
	test2 = new StringBuffer(test1.toString());
	System.out.println("test2にtest1を代入しました.");
	
	System.out.println("test1が指す文字列は "+test1+" です.");
	System.out.println("test2が指す文字列は "+test2+" です.");

	//test1を反転させる.
	test1.reverse();

	System.out.println("test1が指す文字列は "+test1+" です.");
	System.out.println("test2が指す文字列は "+test2+" です.");

	    
    }
}
実行結果
[onisi@m449 ~/Java] java String2
test1を宣言しました.
test1に文字列 ABCDEFGHIJKLMN を割り当てました.
test2を宣言しました.
test2にtest1を代入しました.
test1が指す文字列は ABCDEFGHIJKLMN です.
test2が指す文字列は ABCDEFGHIJKLMN です.
test1が指す文字列は NMLKJIHGFEDCBA です.
test2が指す文字列は ABCDEFGHIJKLMN です.

課題


| 目次| 1234567891011121314
| 資料| 予定| 課題| 宿題|