情報学部 菅沼ホーム 全体目次

Java 概説

    1. データ型
    2. 演算子
      1. 算術演算子と代入演算子
      2. 関係演算子,等値演算子,及び,論理演算子
      3. ビット演算子とシフト演算子
    3. 制御文
      1. 分岐
      2. 繰り返し
    4. 配列
    5. メソッド
      1. 基本型
      2. 配列の引き渡し
      3. 配列を戻り値
      4. main メソッド
    6. クラス定義
    7. 継承
    8. 変数の有効範囲(スコープ)
  1. データ型(「 Java と C/C++ 」の第3章参照)
    型名           バイト数  値の範囲
    byte             1       -128 ~ 127
    char             2       2バイトの文字
    short            2       -32,768 ~ 32,767
    int              4       -2,147,483,648 ~ 2,147,483,647
    long             8       -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807
    float            4       3.4E±38(有効桁:約 7 桁)
    double           8       1.7E±308(有効桁:約 15 桁)
    boolean                  true, false			
  2. 演算子(「 Java と C/C++ 」の第3章及び第4章参照)

    1. 算術演算子代入演算子
      + : 加算(文字列の結合にも使用される)
      - : 減算
      * : 乗算
      / : 除算(整数どうしの演算の場合,結果の小数点以下は切り捨て)
      % : 余り(実数演算に対しても使用可能)
      = : 代入
      ++ : インクリメント演算子( 1 だけ増加)
      -- : デクリメント演算子( 1 だけ減少)				
    2. 関係演算子等値演算子,及び,論理演算子
      >  より大きい  a > b   式 a の値が式 b の値より大きいとき真
      <  より小さい  a < b   式 a の値が式 b の値より小さいとき真
      >= 以上     a >= b  式 a の値が式 b の値以上のとき真
      <= 以下     a <= b  式 a の値が式 b の値以下のとき真
      == 等しい    a == b  式 a の値と式 b の値が等しいとき真
      != 等しくない  a != b  式 a の値と式 b の値が等しくないとき真
      || 論理和  x || y  式 x が真か,または,式 y が真のとき真
      && 論理積  x && y  式 x が真で,かつ,式 y が真のとき真
      !  否定    ! x      式 x が偽のとき真				
    3. ビット演算子シフト演算子
      | 論理和      x | y   対応するビットのいずれかが 1 のとき真.
      & 論理積      x & y   対応するビットの双方が 1 のとき真
      ^ 排他的論理和 x ^ y   対応するビットが異なるのとき真
      ~ 1の補数     ~ x      ビット毎に 1 と 0 を反転する
      << 左にシフト  x << 3  3 ビット左にシフト.x を 23 倍することに相当.
      >> 右にシフト  x >> 3  3 ビット右にシフト.x を 23 で割ることに相当.
      >>> 右にシフト  x >>> 3  3 ビット右にシフト( C++ における符号無しの整数を右シフトする場合に相当).				

  3. 制御文(「 Java と C/C++ 」の第5章参照)

    論理式: 結果が真( true )または偽( false )となる式

    1. 分岐

      1. if 文
        if (論理式) {
        	文1(複数の文も可)
        	(論理式が真の場合に実行)
        }
        else {
        	文2(複数の文も可)
        	(論理式が偽の場合に実行)
        }					
      2. else if 文
        if (論理式1) {
        	文1(複数の文も可)
        	(論理式1が真の場合に実行)
        }
        else if (論理式2) {
        	文2(複数の文も可)
        	(論理式2が真の場合に実行)
        }
          ・・・
        else {
        	文n(複数の文も可)
        	(いずれの論理式も偽である場合に実行)
        }					
      3. switch 文
        switch (式) {
        	[case 定数式1 :]
        		[文1]
        	[case 定数式2 :]
        		[文2]
        	 ・・・・・
        	[default :]
        		[文n]
        }					
    2. 繰り返し

      1. for 文
        for (初期設定; 論理式; 後処理) {
        	文(複数の文も可)
        	(論理式が真である限り繰り返し実行)
        }					
      2. while 文
        while (論理式) {
        	文(複数の文も可)
        	(論理式が真である限り繰り返し実行)
        }					
      3. do while 文
        do {
        	文(複数の文も可)
        	(論理式が真である限り繰り返し実行,
        	 ただし,最初は必ず実行)
        } while (論理式) ;					

  4. 配列(「 Java と C/C++ 」の第6章参照)

      配列は,複合データ型の一種であり,複数の同じデータ型のデータを処理する場合に利用されます.例えば,
    int u1[] = {1, 2, 3}, u2[] = {1, 2, 3}, u3[];
    int u4[] = new int[3];   // 初期設定しない場合
    u3 = u1;			
    の 1 行目のように宣言すれば,u1,u2 という,1,2,3 で初期設定された 3 つの整数型データを記憶できる領域が確保され,変数名と添え字を利用して,u1[0],u1[1],u1[2],u2[0],u2[1],u2[2] のようにして参照できます.また,u3 に対しては,配列変数であることだけを宣言した変数 u3 を定義しています.

      3 行目において,u1 を u3 に代入しています.しかし,この代入は,整数型の場合のような代入ではありません.つまり,u1 の領域及びそこに記憶されている要素をすべてコピーし,u3 に代入しているわけではありません.ここでは,u1,u2,u3 を C/C++ 言語におけるポインタとしてとらえた方が理解しやすいと思います.つまり,3 行目の代入によって,u1 に記憶されているアドレスが u3 に記憶され,u1 と u3 が同じ領域を指しているという意味です.実際,u1 の値を変更すれば,u3 の値も変化します(逆も同様).ただし,値は同じであっても,u2 は,u1 や u3 とは異なる配列です.このことを概念的に示せば以下のようになります.

      多次元の配列を扱うことも可能です.例えば,
    int v1[][] = {{10, 20, 30}, {40, 50, 60}}, v2[][] = {{10, 20, 30}, {40, 50, 60}}, v3[][];
    v3 = v1;			
    の 1 行目の記述によって 2 行 3 列の表に対応する配列 v1,v2 が生成されます.v3 に対しては,2 次元配列であることだけを宣言していますが,2 行目の記述によって,v3 も,v1 と同じ 2 行 3 列の配列になります.そのイメージは,new 演算子を使用した C++ の場合と同じく,以下のようになります.

      例えば,
    int vp1[] = v1[0];   // v1,v3 の 1 行目
    int vp2[] = v1[1];   // v1,v3 の 2 行目			
    のように,各行を 3 つの要素からなる 1 次元配列として扱うことも可能です.勿論,vp1 と v1[0] は同じ場所を指していますので,例えば,vp1[1] の値を変更すれば,v1[0][1] の値も変化します(逆も同様).しかし,すべてのデータが連続した領域に確保されるとは限らないため,C++ における配列のように,異なる行のデータを,連続した 1 次元配列とみなして参照することはできません.

      以下に示すような方法で 2 次元配列を定義することも可能です.この例では,上に示した配列と同じサイズで,かつ,同じ値を持つ配列を定義しています.
    int v1[][] = new int [2][];
    for (int i1 = 0; i1 < 2; i1++) {
    	v1[i1] = new int [3];
    	for (int i2 = 0; i2 < 3; i2++)
    		v1[i1][i2] = 10 * (3 * i1 + i2 + 1);
    }			
    さらに,以下に示すような方法を使用すれば,初期設定も行うことが可能です.
    int x1[] = {10, 20, 30};
    int x2[] = {40, 50, 60};
    int v1[][] = {x1, x2};			

  5. メソッド(「 Java と C/C++ 」の第7章参照)

      関数は,データを受け取り,何らかの処理を行い,その結果を返す手続きの集まりです.Java においては,main 関数も含み,全てのプログラムがいずれかのクラスに含まれています.従って,C++ におけるメンバー関数に相当するもの(以後,関数をメソッドと呼びます)だけが存在します.メソッド内では,与えられた情報(引数リスト)に基づき何らかの処理を行い,その結果を戻り値( 1 つの値)として返します.メソッド名は,同じクラス内で唯一の名前である必要がありますが,引数の数や引数の型が異なる場合は同じ名前のメソッドが存在しても構いません(関数名の多重定義関数名のオーバーロード).

    1. 基本型

        メソッドにデータを渡し,その結果を得るためには様々な方法が考えられます.最も簡単な方法は,以下に示すプログラム例( 2 つのデータの和を求めるメソッド)のように,引数としてデータ(厳密には,データのコピー)を渡し,戻り値として結果を受け取る方法です.なお,main メソッドから他のメソッドを直接呼ぶとき,main メソッドに対しては static 宣言(クラス定義参照)が必要であるため,メソッド add も static にしなければならず,

      import java.io.*;
      
      class Test {
      					// メソッド main
      	public static void main (String[] args)
      	{
      		int x = 10, y = 20;
      
      		System.out.println("和 = " + add(x, y));
      	}
      					// メソッド add
      	static int add(int a, int b)
      	{
      		return a + b;
      	}
      }
      				

      のように記述する必要があります.そこで,以下の例においては,次のプログラムに示すように,main メソッドの中で Example クラスのインスタンス(クラス定義参照)を生成し,その中でメソッドを呼ぶようにしています.なお,コンストラクタとは,クラスのオブジェクトを定義したときに自動的に呼ばれるメソッドであり,オブジェクトに対する初期設定を行います.

      import java.io.*;
      
      class Test {
      					// メソッド main
      	public static void main (String[] args)
      	{
      		Example ex = new Example();
      	}
      }
      
      class Example {
      					// コンストラクタ
      	Example()
      	{
      		int x = 10, y = 20;
      
      		System.out.println("和 = " + add(x, y));
      	}
      					// メソッド add
      	int add(int a, int b)
      	{
      		return a + b;
      	}
      }
      				

    2. 配列の引き渡し

        引数として int や double など,基本型のデータを渡す場合,その値がコピーされて渡されるため,メソッド内において引数(上の例におけるメソッド add 内の a や b )の値を変更しても,メソッドを呼んだ側の x や y の値はその影響を受けません.上の例のように,1 つの結果だけを求める場合は問題ありませんが,例えば,和と差のように,複数の結果を得たい場合はどのようにすればよいでしょうか.その一つの方法は,配列を利用することです.配列を引数にすることは,アドレスを引数にすることに相当し,アドレスがコピーされて渡されてもその指す場所は同じであるため,配列要素をメソッド内で変更できるからです.下の例では,和と差を配列に入れて返しています.

      import java.io.*;
      
      class Test {
      					// メソッド main
      	public static void main (String[] args)
      	{
      		Example ex = new Example();
      	}
      }
      
      class Example {
      					// コンストラクタ
      	Example()
      	{
      		int x = 10, y = 20;
      		int z[] = new int [2];
      
      		add(x, y, z);
      		System.out.println("和 = " + z[0] + "  差 = " + z[1]);
      	}
      					// メソッド add
      	void add(int a, int b, int c[])
      	{
      		c[0] = a + b;
      		c[1] = a - b;
      	}
      }
      				

        後に述べるように,クラスのオブジェクトをメソッドの引数とする場合もあります.C++ においては,幾つかの方法を利用できましたが,Java においては,記述的には上で示したプログラムにおける変数 a や b と同じ方法で渡します.しかし,その実態は,配列を引数とする場合と同様,オブジェクトに対するポインタがコピーされて渡されます.そのような意味から,C++ における参照渡しによく似ています.従って,記述方法においては変数 a や b と同じですが,メソッド内でオブジェクトの値を変更すれば,そのメソッドを呼んだ側の値も変化します.

    3. 配列を戻り値

        上の例では,結果を引数として返していましたが,配列(アドレス)を使用すれば,以下に示す例のように,戻り値を利用して複数データを返すことも可能です.

      import java.io.*;
      
      class Test {
      					// メソッド main
      	public static void main (String[] args)
      	{
      		Example ex = new Example();
      	}
      }
      
      class Example {
      					// コンストラクタ
      	Example()
      	{
      		int x = 10, y = 20;
      		int z[];
      
      		z = add(x, y);
      		System.out.println("和 = " + z[0] + "  差 = " + z[1]);
      	}
      					// メソッド add
      	int [] add(int a, int b)
      	{
      		int c[] = new int [2];
      
      		c[0] = a + b;
      		c[1] = a - b;
      
      		return c;
      	}
      }
      				

    4. main メソッド

        例えば,
      java add 2 3				
      とキーボードから入力すると,3 つの値 2 と 3 の和を計算し,その結果をディスプレイに出力したいような場合が存在します(下に示すプログラム例).このような場合,2 や 3 が main メソッドの引数とみなされます.ただし,main メソッドの場合は,引数の受け渡し方が以下のように決まっており,args に各引数に対応する文字列が入ります.
      public static void main ( String args[] )				
      import java.io.*;
      
      public class Test {
      	public static void main(String args[]) throws IOException
      	{
      		int i1, k, sum = 0;
      	/*
      		 引数の内容の出力
      	*/
      		System.out.println("     引数の数 " + args.length);
      
      		for (i1 = 0; i1 < args.length; i1++) {
      			k = Integer.parseInt(args[i1]);   // 文字を整数に変換
      			System.out.println("     " + (i1+1) + " 番目の引数 " + k);
      			sum += k;
      		}
      	/*
      		 結果の表示
      	*/
      		System.out.println("結果=" + sum);
      	}
      }
      				

  6. クラス定義(「 Java と C/C++ 」の第7章参照)

      住所録を作成する際のように,氏名,住所,電話番号などをまとめて一つのデータとして扱いたい場合があります.数学の例で言えば,複素数などが相当します.複素数は,実数部と虚数部という 2 つの実数データの組からなっており,それらのデータは常に一緒に扱われます.

      クラスの内部には,データだけではなく,そのデータを処理するためのメソッドも定義できます.そして,データやメソッドの対して参照制限を設けることが可能です.クラスの定義方法を一般的に記述すれば以下のようになります.
    [クラス修飾子] クラス識別子 {
    	クラス本体(変数やメソッドの定義)
    }			
      クラス修飾子は,以下のいずれかから選択します.クラス修飾子を使用せずにクラスを定義すると,同じパッケージ内にあるクラスだけがこのクラスにアクセスできるものと自動的に判断されます.

    1. public  すべてのクラスからアクセス可能になります.同じファイル内で public 宣言できるのは一つのクラスだけです.
    2. abstract  抽象クラスであることを示します.
    3. final  このクラスからほかのクラスを派生できないことを宣言するために使用します(次節参照).

      C++ のように関数や変数をまとめてそのアクセス権等を定義するようなことはせず,個々のメソッドや変数の定義に修飾子として直接記述します.メソッドを定義するための修飾子は 8 つあり,以下の 3 つのグループの中から一つずつ選択して使用します(必ず,3 つを指定しなければならないわけではありません).ただし,修飾子の組み合わせによっては,矛盾が生じるような場合もありますので注意してください.

    1. public,protected,private (何も指定しないと,同じパッケージからだけアクセス可能となる)

      • public  このメソッドをすべてのクラスからアクセスできます.異なるパッケージからアクセスしたい場合は,必ず指定する必要があります.
      • protected  同じパッケージ及びクラスの派生クラスだけからアクセスできます(次節参照).
      • private  クラス及びそれを継承したクラスのオブジェクトだけからアクセスできます.

    2. static

      • static  通常のメソッドは,各オブジェクトに結びつき,そのオブジェクトからアクセス可能ですが,static 指定されたメソッドは,クラスに結びつき,特別に指定しない限りオブジェクトからはアクセスできません.したがって,アクセスも,「オブジェクト名.メソッド名」ではなく,「クラス名.メソッド名」というようにして行います.例えば,三角関数や対数関数の値を計算するために利用される Math クラスのメソッドは static 宣言されています.したがって,ある値 x の正弦を計算したいときには「 Math.sin(x) 」のような形で使用します.

    3. abstract,final,native,synchronized

      • abstract  抽象メソッドであることを意味しています.
      • final  階層の最も下のメソッドであることを意味し,それより下位のクラスでは,同じ名前のメソッドを定義しオーバーライド(他で定義されたメソッドを,書き換えて再定義すること)することができません.
      • native  他の言語で記述されたメソッドであることを意味します.
      • synchronized  オブジェクトが複数のオブジェクトから同時に実行されることを制限するために使用されます.

      変数の修飾子は 7 つあります.以下の 2 つのグループから一つずつを選択して使用します.メソッドの修飾子と同様,必ず修飾子を付けなければならないわけではありません.なお,修飾子を付加できるのは,メソッド外で定義された変数だけです.

    1. public,protected,private (何も指定しないと,同じパッケージからだけアクセス可能となる)

      • public  この変数をすべてのクラスからアクセスできます.異なるパッケージからアクセスしたい場合は,必ず指定する必要があります.
      • protected  同じパッケージ及びクラスの派生クラスだけからアクセスできます(次節参照).
      • private  クラス内及びそのクラスを継承したクラス内のメソッドだけからアクセスできます.継承したクラスで追加されたメソッドからはアクセスできません.

    2. static,final,transient,volatile

      • static  メソッドの場合と同様,クラスに結びついた変数です.したがって,オブジェクトごとに値を変化させるようなことはできません.アクセスも,「オブジェクト名.変数名」ではなく,「クラス名.変数名」というようにして行います.例えば,Math クラスの PI(π) などが相当します.
      • final  クラスのオブジェクト全体で使用可能な定数となります.
      • transient  未使用.
      • volatile  非同期方式の多重処理で使用され,この変数は使われるたびにメモリからロードされ,また,メモリに格納されます.

      全てのデータを private に指定し,また,全てのメソッドのアクセス権を指定しないで Complex というクラスを定義すると,以下のようになります.

    01	import java.io.*;
    02	
    03	class Test {
    04		public static void main (String[] args)
    05		{
    06			Complex x = new Complex (1.0, 0.0);   // 初期設定を行う場合
    07			Complex y = new Complex ();   // 初期設定を行わない場合
    08	
    09			x.print();
    10			y.set(5.1, 1.5);
    11						// x,y が private であるため,以下の処理は不可能
    12						//	y.real      = 5.1;
    13						//	y.imaginary = 1.5;
    14			y.print();
    15		}
    16	}
    17				// クラス Complex
    18	class Complex {
    19		private double real;
    20		private double imaginary;
    21						// 引数のないコンストラクタ
    22		Complex() {};
    23						// 引数のあるコンストラクタ
    24		Complex(double a, double b)
    25		{
    26			real      = a;
    27			imaginary = b;
    28		}
    29						// 値の設定するためのメソッド
    30		void set(double a, double b)
    31		{
    32			real      = a;
    33			imaginary = b;
    34		}
    35						// 出力するためのメソッド
    36		void print()
    37		{
    38			System.out.println("実数部 = " + real + ", 虚数部 = " + imaginary);
    39		}
    40	}
    			
      コンストラクタとは,クラス名と同じ名前のメソッドであり,クラスのインスタンスが生成されたとき( Complex 型の変数が定義されたとき,06,07 行目),最初に呼ばれるメソッドです.初期設定を行うメソッドと言って良いかもしれません.この例では,引数の無い場合とある場合に対する 2 種類のコンストラクタを定義しています( 22 行目,24 行目~ 28 行目).なお,Java においては,デストラクタは存在しません.

      Java においては,上の例に示すように,クラスのインスタンスを生成するためには必ず new 演算子を利用します.この方法は,C++ における,
    Complex *x = new Complex (1.0, 0.0);   // 初期設定を行う場合
    Complex *y = new Complex ();   // 初期設定を行わない場合			
    の形式と非常に良く似ています.実際,以下のプログラム例(全てのデータやメソッドに対してアクセス権を指定していない)に示すように,変数 y1 や y2 は,生成されたオブジェクトへのポインタと考えた方が妥当です.右図は,y1 を y2 に代入し,「 y2.imaginary = 4.0; 」を実行した後の状態を示しています( y1.imaginary の値も 4.0 になる).

    import java.io.*;
    
    class Test {
    	public static void main (String[] args)
    	{
    		Complex y1 = new Complex (5.0, 0.0);
    		Complex y2;
    
    		System.out.println("y1 : 実数部 = " + y1.real + ", 虚数部 = " + y1.imaginary);
    		y2 = y1;
    		System.out.println("y2 : 実数部 = " + y2.real + ", 虚数部 = " + y2.imaginary);
    		y2.imaginary = 4.0;
    		System.out.println("y1 : 実数部 = " + y1.real + ", 虚数部 = " + y1.imaginary);
    		System.out.println("y2 : 実数部 = " + y2.real + ", 虚数部 = " + y2.imaginary);
    	}
    }
    			// クラス Complex
    class Complex {
    	double real;
    	double imaginary;
    					// 引数のないコンストラクタ
    	Complex() {};
    					// 引数のあるコンストラクタ
    	Complex(double a, double b)
    	{
    		real      = a;
    		imaginary = b;
    	}
    }
    			
    (出力)
    y1 : 実数部 = 5.0, 虚数部 = 0.0
    y2 : 実数部 = 5.0, 虚数部 = 0.0
    y1 : 実数部 = 5.0, 虚数部 = 4.0
    y2 : 実数部 = 5.0, 虚数部 = 4.0			

  7. 継承(「 Java と C/C++ 」の第8章参照)

      クラスにおいて,継承は重要な機能です.Window のプログラムを考えてみてください.多くのアプリケーションにおいて Window を利用していますが,その基本的構成はほとんど同じです.もし,Window アプリケーションを作成するたびに,その全てに関するプログラムを書かなければならないとしたら大変な作業になります.基本的な Window の機能を持つクラスを定義しておき,個々の Window アプリケーションは,そのクラスを利用できるとしたら非常に便利です.

      継承を利用すれば,指定されたクラス(単一のクラスだけ)の機能を受け継ぎ,新しいクラスに必要な機能の追加・修正だけを行えばよくなります.例えば,以下のプログラム(あまり良い例ではありませんが)においては,クラス Number は,クラス Base を継承しています.このとき,元になったクラス( Base )をスーパークラス,そのクラスを継承したクラス( Number )をサブクラスと呼びます.

      スーパークラスにおいて,「 protected 」指定されたデータやメソッドは,そのクラスを継承したサブクラスだけから参照可能です.private 指定されたデータやメソッドは,スーパークラスのメソッド及びそれを継承したサブクラスのメソッドだけから参照可能であり,サブクラスにおいて追加されたメソッドからは参照不可能です.また,すべてのメンバーがほとんどそのままの状態( private は private,public は public 等)で継承されます.

      しかし,コンストラクタは継承されませんので,スーパークラスにパラメータを必要とするコンストラクタが存在する場合は,super を使用して明示的に呼び出します.

    import java.io.*;
    
    class Test {
    	public static void main (String[] args)
    	{
    		Number x = new Number (10, 2);
    		Number y = new Number (5, 4);
    
    		x.add();
    		x.print();
    		y.sub();
    		y.print();
    	}
    }
    			// クラス Base
    class Base {
    	protected int n;
    	protected int step;
    					// コンストラクタ
    	Base (int sp)
    	{
    		step = sp;
    	}
    					// 出力
    	void print() { System.out.println("value = " + n); }
    					// 加算
    	void add() { n += step; }
    					// 減算
    	void sub() { n -= step; }
    }
    			// クラス Number
    class Number extends Base   // Base の継承
    {
    					// コンストラクタ
    	Number (int n1, int sp)
    	{
    		super(sp);   // スーパークラスのコンストラクタの呼び出し
    		n = n1;
    	}
    }
    			
      Java には,C++ のように,派生クラスに関して多重継承の機能がありません.そこで,その機能の一部を補うのがインタフェースです.クラスの階層構造の中で,上下関係にない複数クラス間で情報を交換する(共通の変数やメソッドの利用する)ための機能であり,クラスと同様以下のようにして定義されます.
    public interface インタフェース名 extends 親インタフェース名 [ , ・・・ ] {
    	// 変数:static final とみなされる
    	// メソッド宣言:abstract とみなされる
    }			
      クラスは,複数のインタフェースを継承可能です( implements の後ろに複数のインタフェースをカンマで区切って並べることができます).ただし,継承可能なものは,メソッドの宣言と static な変数だけであり,継承したクラスが抽象クラスでない限り,インタフェース内で宣言されたメソッドの内容を定義(オーバーライド)してやる必要があります.

  8. 変数の有効範囲(スコープ)(「 Java と C/C++ 」の5.3 節参照)

    01	/****************************/
    02	/* 変数の有効範囲(スコープ) */
    03	/*      coded by Y.Suganuma */
    04	/****************************/
    05	import java.io.*;
    06	
    07	public class Test {
    08		public static void main(String args[]) throws IOException
    09		{
    10				// ブロック
    11			int x = 10;
    12			if (x > 5) {
    13				System.out.printf("block x %d\n", x);
    14	//			int x = 15;   // 許されない
    15				int y = 20;
    16				System.out.printf("block y %d\n", y);
    17			}
    18			sub();
    19			System.out.printf("x %d\n", x);
    20	//		System.out.printf("y %d\n", y);   // y が未定義
    21				// クラス
    22					// クラス
    23			Example2 ex = new Example2();
    24			ex.sub1();
    25			ex.sub2();
    26			System.out.printf("public member( pub ) %d\n", ex.pub);
    27		}
    28	
    29		/************/
    30		/* 関数 sub */
    31		/************/
    32		static void sub()
    33		{
    34			int x = 40;
    35			System.out.printf("   sub x %d\n", x);
    36		}
    37	}
    38	
    39	/*******************/
    40	/* クラス Example1 */
    41	/*******************/
    42	class Example1 {
    43	
    44		private int pri;
    45		protected int pro;
    46		public int pub;
    47	
    48		Example1() {
    49			pub = 1000;
    50			pri = 2000;
    51			pro = 3000;
    52		}
    53	
    54		void sub1() {
    55			System.out.printf("sub1 pub %d pri %d pro %d\n", pub, pri, pro);
    56		}
    57	}
    58	
    59	/*******************/
    60	/* クラス Example2 */
    61	/*******************/
    62	class Example2 extends Example1 {
    63		void sub2() {
    64			System.out.printf("sub2 pub %d pro %d\n", pub, pro);
    65	//		System.out.printf("sub2 pri %d\n", pri);   // 許されない
    66		}
    67	}
    			
      まず,11 行目において,変数 x が定義され,10 で初期設定されています.この変数 x は,この位置から main メソッドが終わる 27 行目まで有効になります.12 ~ 17 行目の if ブロック内の 13 行目において,変数 x の値が出力されていますが,当然,その結果は,11 行目で宣言されたときの値になります.14 行目において,再び,変数 x を宣言しようとしていますが,C++ とは異なり,Java では,その内部のブロック内であっても,同じ名前の変数を定義することは許されません.

      しかし,異なる変数の定義は許されます.15 行目で宣言された変数 y の有効範囲内は,この位置から if ブロックの最後である 17 行目までとなります.実際,20 行目のような出力を行おうとすれば,エラーになってしまいます.

      上で述べたように,あるブロックの外側で定義されている変数と同じ名前の変数を,その内側のブロックで再定義することは許されませんが,メソッドの外側で定義されている変数と同じ名前の変数を,メソッド内で定義することは可能です.例えば,42 ~ 57 行目のクラス Example1 の定義において,3 つの変数( pri,pro,pub )がメソッドの外側で定義されていますが,これらの変数と同じ名前の変数をメソッド Example1 や sub1 の内部で定義することは可能です.しかし,そのようにすると,メソッド内ではそれらの変数が優先され,44 ~ 46 行目の変数を参照できなくなってしまいます.従って,メソッドの外側で定義され変数と同じ名前の変数を,メソッド内で使用することは避けた方が良いと思います.

      18 行目においてメソッド sub を呼んでいます.34 行目では,変数 x を宣言し,35 行目において,その値を出力しています.当然,34 行目の宣言を行わなければ,エラーになってしまいますし,また,34 行目の宣言によって,11 行目で宣言された x の値が影響を受けることはありません( 19 行目の出力文に対応する結果参照).このように,変数 x や y のように,あるブロック(メソッドを含む)内だけで有効な変数を,ローカル変数と呼びます.以上,11 ~ 19 行目内の出力文(メソッド sub 内の出力文を含む)によって,以下に示すような出力が得られます.
    block x 10
    block y 20
       sub x 40
    x 10				
      次に,クラスに付いて考えてみます.42 ~ 57 行目においてクラス Example1 が定義され,62 ~ 67 行目では,クラス Example1 を継承する形で,クラス Example2 が定義されています.23 行目において,Example2 のインスタンス ex を生成し,24 行目では,クラス Example1 から継承したメソッド sub1 を通して,3 つの変数を出力しています.このときは,3 つの変数の値がそのまま出力されます.しかし,25 行目では,クラス Example2 に追加されたメソッド sub2 を通して各変数を出力しています.ただし,この場合は,親クラス Example1 の private メンバー変数 pri を参照することができない点に注意してください.また,26 行目のようなクラスの外側からの参照においては,pubulic メンバー変数 pub だけを参照可能です.なお,private 指定は,同じクラス内のメソッドだけから,protected 指定は,同じクラス,及び,そのクラスを継承したクラスだけから,また,public 指定は,どこからでも参照可能なことを意味します.以上,23 ~ 26 行目内の出力文によって,以下に示すような出力が得られます.
    sub1 pub 1000 pri 2000 pro 3000
    sub2 pub 1000 pro 3000
    public member( pub ) 1000				

情報学部 菅沼ホーム 全体目次