私のホームページへ - 前の授業へ - 次の授業へ

情報処理IIIA(Javaプログラミング入門)第11回

目次
  1. クラスとメソッド(5)
  2. 演習11
  3. レポート課題

クラスとメソッド(5)

クラス変数

これまで説明した通り、変数は宣言すれば使えます。 しかし、いつまでも使い続けられるわけではありません。 例えば、メソッド定義

static void printStars (int m) {
   int i;
   for (i = 0; i < m; i++) {
      System.out.print("*");
   }
}

での変数 i は、メソッド呼び出しの際に用意されます。 しかし、この呼び出しが終了しますと、変数 i は使えなくなります。 このような変数は局所変数local variable)とよばれます。

データを局所変数に格納しても、他のメソッドからはそのデータは利用できません。 複数のメソッドの間でデータを共有するには、大域変数global variable)というものを用います。 大域変数とは、プログラムのどこからでも使える変数です。 あるメソッドで大域変数にデータを格納し、他のメソッドでそれを取り出すことができます。

実は、Javaには大域変数は用意されていません。 これは、クラス変数class variable)というもので代用します。 クラス変数とは、クラスに割り当てられる変数と考えてください。 クラス変数と対照的なのがインスタンス変数(すなわちフィールド)です。 クラスのインスタンスを生成しますと、インスタンスごとにインスタンス変数が用意されます。 一方、クラス変数は、インスタンスをいくら生成しても、クラスにひとつだけ用意されます。 次の図は、クラス変数とインスタンス変数のイメージです。

図11.1 クラス変数とインスタンス変数

次のプログラムは、出勤時刻に関して遅刻の回数を数えるものです。 AttendingTime.java の3行目で、クラス変数 lateCount を用意します。 クラス変数は、フィールドと同じように指定します。 違いは、キーワード static を書くところです。

AttendingTime.java
/* 1*/ class AttendingTime {
/* 2*/    int hour, minute;
/* 3*/    static int lateCount = 0;
/* 4*/    AttendingTime (int h, int m) {
/* 5*/       this.hour = h;
/* 6*/       this.minute = m;
/* 7*/    }
/* 8*/    void checkLate () {
/* 9*/       if (540 < 60 * this.hour + this.minute) {
/*10*/          lateCount++;
/*11*/       }
/*12*/    }
/*13*/    int getLateCount () {
/*14*/       return lateCount;
/*15*/    }
/*16*/ }
AttendingTimeTest.java
/* 1*/ class AttendingTimeTest {
/* 2*/    public static void main (String[] args) {
/* 3*/       AttendingTime dec01 = new AttendingTime(8, 55);
/* 4*/       dec01.checkLate();
/* 5*/       AttendingTime dec02 = new AttendingTime(9, 10);
/* 6*/       dec02.checkLate();
/* 7*/       AttendingTime dec03 = new AttendingTime(9, 5);
/* 8*/       dec03.checkLate();
/* 9*/       System.out.println(dec03.getLateCount());
/*10*/    }
/*11*/ }
b00a001@Ampere:~/java% java AttendingTimeTest
2
b00a001@Ampere:~/java%

定数

大域変数を用いて定数constant)を表すことがよくあります。 定数とは、常に変わらない値のことです。 プログラムに定数を直接書きますと、それが何を表しているのか分かりにくいものです。 そこで、大域変数に定数を代入しておき、定数の代わりに変数名を書きます。 定数に分かりやすい名前をつけ、プログラムを読みやすくするのです。

定数を表す変数へは、新たな代入が行われないようにしなくてはいけません。 変数を宣言するときに、キーワード final を書きますと、値の変更が禁止されます。 これによって、どの変数が定数を表すのかが明確になります。

上記のプログラムでは、AttendingTime.java の9行目の条件

540 < 60 * this.hour + this.minute

540 が何を表しているのかが分かりにくいでした。 これは始業時刻9:00の絶対時刻(分)です。 定数を

final static int OPENINGHOUR = 9, OPENINGMINUTE = 0;

と定め、条件を

60 * OPENINGHOUR + OPENINGMINUTE
   < 60 * this.hour + this.minute

と書きますと、出勤時刻が始業時刻以後ならば…と読めるわけです。

AttendingTime.java(第2版)
/* 1*/ class AttendingTime {
/* 2*/    int hour, minute;
/* 3*/    static int lateCount = 0;
/* 4*/    final static int OPENINGHOUR = 9, OPENINGMINUTE = 0;
/* 5*/    AttendingTime (int h, int m) {
/* 6*/       this.hour = h;
/* 7*/       this.minute = m;
/* 8*/    }
/* 9*/    void checkLate () {
/*10*/       if (60 * OPENINGHOUR + OPENINGMINUTE
/*11*/              < 60 * this.hour + this.minute) {
/*12*/          lateCount++;
/*13*/       }
/*14*/    }
/*15*/    int getLateCount () {
/*16*/       return lateCount;
/*17*/    }
/*18*/ }

クラス変数とクラスメソッド

ここで、クラスメソッドについて思い出してください。 クラスメソッドを定義するときは、キーワード static を用いました。 また、呼び出しのときはインスタンスを伴いませんでした。

クラス変数とクラスメソッドは、これまで同じクラスのものしか使いませんでした。 他のクラス class のクラス変数 variable は、class.variable と書くと使えます。 同様に、他のクラス class のクラスメソッド method(...) は、class.method(...) と書くと使えます。

上記のプログラムでは、遅刻の回数を表示するのに、getLateCount メソッドを用いて

System.out.println(dec03.getLateCount());

と書きました。 このメソッドは、定義

int getLateCount () {
   return lateCount;
}

を見ると分かりますが、単にクラス変数 lateCount の値を返すだけで、インスタンス dec03 のデータは使っていません。 そこで、クラスメソッドとして

static int getLateCount () {
   return lateCount;
}

と定義し直すことにします。 このメソッドは、これまでのクラスメソッドのように

System.out.println(getLateCount());

と書いても呼び出せません。 メソッドが定義されているクラス(AttendingTime)と呼び出すクラス(AttendingTimeTest)が異なるからです。

System.out.println(AttendingTime.getLateCount());

と書くと呼び出せます。

AttendingTime.java(第3版)
/* 1*/ class AttendingTime {
/* 2*/    int hour, minute;
/* 3*/    static int lateCount = 0;
/* 4*/    final static int OPENINGHOUR = 9, OPENINGMINUTE = 0;
/* 5*/    AttendingTime (int h, int m) {
/* 6*/       this.hour = h;
/* 7*/       this.minute = m;
/* 8*/    }
/* 9*/    void checkLate () {
/*10*/       if (60 * OPENINGHOUR + OPENINGMINUTE
/*11*/              < 60 * this.hour + this.minute) {
/*12*/          lateCount++;
/*13*/       }
/*14*/    }
/*15*/    static int getLateCount () {
/*16*/       return lateCount;
/*17*/    }
/*18*/ }
AttendingTimeTest.java
/* 1*/ class AttendingTimeTest {
/* 2*/    public static void main (String[] args) {
/* 3*/       AttendingTime dec01 = new AttendingTime(8, 55);
/* 4*/       dec01.checkLate();
/* 5*/       AttendingTime dec02 = new AttendingTime(9, 10);
/* 6*/       dec02.checkLate();
/* 7*/       AttendingTime dec03 = new AttendingTime(9, 5);
/* 8*/       dec03.checkLate();
/* 9*/       System.out.println(AttendingTime.getLateCount());
/*10*/    }
/*11*/ }

なお、遅刻の回数を求めるのに、メソッド getLateCount を用いず、クラス変数 lateCount の値を直接取り出す方法もあります。 この場合でも、クラスが異なる理由から、

System.out.println(lateCount);

では値は取り出せません。

System.out.println(AttendingTime.lateCount);

と書くと取り出せます。

インスタンスメソッドとクラスメソッド

ここで、インスタンスメソッドとクラスメソッドの違いをまとめます。

インスタンスメソッドとクラスメソッドのどちらを使うべきかは一概には言えません。


演習11

今、1999年5月号創刊の月刊誌があるとします。 ある人が1999年8月号からその雑誌を買い続けましたが、2000年12月号を最後に買うのをやめてしまいました。 結局17冊買ったことになります。 創刊号は通巻1号で、最後に買ったのは通巻20号です。 もし創刊号から買っていれば、20冊になっていたはずです。

この話を次のようにプログラムにしました。 このプログラムが動くように Magazine クラスを定義してください。 (ヒント: count は、引数が Magazine クラス2つで返り値が int 型であるクラスメソッドです。)

MagazineTest.java
class MagazineTest {
   public static void main (String[] args) {
      Magazine firstIssue = new Magazine(Magazine.FOUNDYEAR, Magazine.FOUNDMONTH);
      Magazine startBuy = new Magazine(1999, 8);
      Magazine endBuy = new Magazine(2000, 12);
      System.out.println(Magazine.count(startBuy, endBuy));
      System.out.println(firstIssue.totalNumber());
      System.out.println(endBuy.totalNumber());
      System.out.println(Magazine.count(firstIssue, endBuy));
   }
}
b00a001@Ampere:~/java% java MagazineTest
17
1
20
20
b00a001@Ampere:~/java%

レポート課題

今日の演習11にしたがってJavaプログラムを作成し、konishi@twcu.ac.jpあてにメールでそのプログラムを提出してください。 メールには、学生番号、氏名、科目名、授業の日付けを明記してください。


私のホームページへ - 前の授業へ - 次の授業へ

このページの複製は、東京女子大学学内に限り許可します。 このページへのリンクを許可します。
2000年12月10日更新
製作・著作:小西善二郎<konishi@twcu.ac.jp>