戻る

フィールド

   これまでクラスのメンバーとして、メソッドだけを扱ってきた。
  クラスは、メソッドの他にも変数をメンバーにする事が出来る。これをフィールドという。

   例えば、次のクラスfieldには、commonというフィールドがある。

   public class Field {
    static int common; ・・・・・・・・・・・・・フィールド

    public static void set(int n) { ・・・・・メソッド
    …
    }

    public static void show( ) { ・・・・・・・メソッド
    …
    }

    public static void main(String[ ] args) { ・・・メソッド
    …
    }
   }

フィールドの宣言

   これまで使ってきた変数は、次のように宣言してきた。

   型名 変数名;

   例えば、次のように

   int num;
   char c;

   ところで、いま見たフィールドの宣言では「型名」の前にstaticがついていた。

   public class Field {
    static int common; ・・・・・フィールドの宣言
    …
    …
   }

   実は、フィールドの宣言と言えども、特にstaticをつけなければいけないというわけではない。
  しかし、staticのついたメソッドからそのフィールドを参照するためには、フィールドの宣言にもstaticをつけなければならない。

   public class Field {
    static int common; ・・・・・staticのついたフィールド

    public static void method_1(……) { ・・・staticのついたメソッド
    …
    }

    public void method_2(……) { ・・・staticのつかないメソッド
    …
    }
   }

   たとえば、上のmethod_1はstaticがついているので、method_1の中でcommonを使う事が出来る。
  しかし、method_2はstaticがついていないので、method_2の中でcommonを使う事は出来ない。

   サンプル:Field.java

   //
   //Field.java---フィールドの追加
   //
   public class Field {
    static int common;

    public static void set(int n) {
     common = n;
    }

    public static void show( ) {
     System.out.println(common);
    }

    public static void main(String[ ] args) {
     set(112741);
     show( );
    }
   }

   実行例

   $ java Field
   112741
   $ _

ローカル変数とフィールド

   ある変数を宣言する時、それをローカル変数にする事も、フィールドにする事も出来る。

   public class SomeClass {
    static int x; ・・・・・フィールド

    public static void main(String[ ] args) {
     int y; ・・・・・ローカル変数
     {
      int z; ・・・ローカル変数
      …
     }
      …
    }
   }

   例えばこの例では、xはクラスのメンバーなのでフィールド、yはメソッドの中で宣言されているのでローカル変数である。
  また、ブロックの中で宣言されているzもローカル変数である。
   では、ローカル変数とフィールドの違いは何だろう。

   「ローカル変数とフィールドの違い」をテストするため、前節のField.javaに出て来たフィールドcommonを普通のローカル変数にしてみる。

   public class Field {
    static int common; Field.javaではここで宣言されていた
    …
    …

    ↓

   public class Field_1 {
    public static void set(int n) {
     int common; ・・・・・staticを消し、今度はローカル変数にする
     common = n;
    }

    public static void show( ) {
     System.out.println(common);
    }

    public static void main(String[ ] args) {
     set(112741);
     show( );
    }
   }

   なお、ローカル変数にはstaticをつけられないので、今度のバージョンではcommonの宣言でstaticを取っている。
  この書き換えたField_1.javaをコンパイルすると、次のようにエラーになってしまう。

   $ java Field_1.java
   Field.java:11: シンボルを解釈処理できません。
   シンボル:変数 common
   位置  :Field_1のクラス
     System.out.println(common);
                   ^
   エラー1個
   $ _

   ここに「ローカル変数とフィールドの違い」が表れている。何故コンパイルエラーになってしまったのか?

スコープ

   「ローカル変数」と「フィールド」で大きく違うのは、そのスコープである。スコープというのは、
  その名前が使えるソースファイルの範囲の事である。
   メソッドの中で宣言されたローカル変数のスコープは、その変数が宣言された位置からメソッドの終わりまでである。

   public static void main)String[ ] args) {
    …
    …
    int y;  ・・・ここから
    …
    …
    …    ・・・ここまでが変数 y のスコープ
   }

   一方、フィールドのスコープはそのクラスに属する全てのメソッドである。(フィールドとメソッドがstaticかどうかで異なる)
  つまりローカル変数は、その変数が宣言されたメソッド内でのみ使う事が出来る。
  これが、前項のアプリケーションがコンパイルエラーになった理由である。
   もし、変数を(同じクラスにある)複数のメソッドから参照したいのなら、それをフィールドとして宣言する必要がある。

ブロック内のローカル変数のスコープ

   ブロック内で宣言されたローカル変数のスコープは、その変数が宣言された位置からブロックの終わりまでである。

   public static void main(String[ ] args) {
    …
    {
    …
    …
    int x;   …変数 z のスコープはここから
    …
    …
    …    …ここまで
    }
    …    …ここで変数 z を使う事は出来ない
   }

   例え、同じメソッド内であってもブロックの終わりを過ぎれば、そのローカル変数を参照する事は出来ない。
  ブロックの外側で宣言されているのと同じ名前のローカル変数を宣言する事は出来ない。

   public static void main(String[ ] args) {
    int x;  ・・・・・・(1)
      …
    {
      …   ・・・・・・(2)
      …
     int y;  ・・・・・・・(3)
      …
     {  ・・・・・・・・・・・(4)
      …  ・・・・・・・・(5)
     }
      …
    }
      …
   }

   例えば、上の(2)の位置でローカル変数 x を宣言しようとしても、すでに(1)でローカル変数 x が宣言されているのでエラーになる。
  また、(4)ではブロックの中に別ブロックを作っている。
  このブロックの(5)の位置でローカル変数 y を宣言しようとしても、すでに(3)でローカル変数 y が宣言されているのでエラーになる。

インスタンスの生成

   これからクラスの新しい使い方を覚える。というよりは、クラス本来の使い方に入っていく。
  すなわち、ある特性を持ったクラスを宣言し、別のクラスからそのクラスの実体であるインスタンスを生成し、利用するといった使い方である。

ユーザー定義型

   「変数とデータ型」の章で説明したようにjavaにはあらかじめ定義された8種類の基本データ型がある。

   byte / short / int / long / float / double / char / boolean

   基本データ型に対して、ユーザーが必要に応じて新しいデータ型を定義する事もできる。これをユーザー定義型という。
  クラスというと何かオブジェクト指向プログラミングと関係ありそうに聞こえるが、要するにユーザー定義型を作る手段にすぎない。
  例えば、文字列用の変数としてString型を使用するが、Stringはクラスとして作られている。
   あるいは、Customerというクラスを作ったとする。するとCustomerは、intとかcharとかと同じように型名の1つとして使う事が出来る。
  したがって、次のようにして変数宣言をする事が出来る。

   Customer someone; ・・・Customerが型名で、someoneが変数名

   後は、このsomeoneの使い方を覚えれば、クラス(という型のデータ)を使う事が出来る。
  なぜならデータ型によって変数の使い方は異なる。クラス型変数の使い方は、他の基本データ型変数の使い方とは異なる。

   これから新しいクラスを宣言し、そのクラスのインスタンスを生成し、利用するまでの流れを見ていく。
  例として、「顧客を管理するクラス」を使う。
   いま顧客データを扱うプログラムがあって、顧客ごとに「顧客番号」と「顧客名」を管理しなければならないとする。

   int id; ・・・・・・・・・顧客番号
   String nama; ・・・顧客名

   このように関連する複数のデータがある時は、それらを1つのクラスにまとめる事が出来る。
  クラス宣言をするには、次のようにする。

   class クラス名{
    //ここにメンバーを並べる
   };

   ※補:このクラス宣言では、classの前にpublicが付いていない事に注意。classの前につけるpublicについては後で説明する。

   クラス名が新しいデータ型の名前になる。顧客データ用のクラス名をCustomerとすれば、
  クラス宣言は次のようになる。最後の } の後ろにセミコロンを付けるのを忘れないように。

   class Customer {
    …
   };

   クラスCustomerには、2つのフィールドを入れる。

   class Customer {
    int id; ・・・・・・・・・・・顧客番号
    String name[20]; ・・顧客名
   };

   さらにクラスCustomerに2つのメソッドを追加する。1つは顧客データを設定するsetDataである。
  このメソッドは、顧客番号と顧客名を引数として受け取り、その値をフィールドに設定する。

   public void setData(int i, String n) {
    id = i;
    name = n;
   }

   もう1つのメソッドは、顧客データ(顧客番号と顧客名)を表示するshowである。

   public void show( ) {
    System.out.println("id = " + id);
    System.out.println("name =" + name);
   }

   これでクラスCustomerが完成した。次にそのリストを示す。

   class Customer {
    int id;      //顧客番号
    String name;  //顧客名

    public void setData(int i, String n); {
     id = i;
     name = n;
    }

    public void show( ) {
     System.out.println("id =" + id);
     System.out.println("name =" + name);
    }
   }

クラス型変数の宣言

   クラスを作ると、新しいデータ型が出来上がる。例えば前項で宣言したクラスCustomerによりCustomerというデータ型が作られる。
  クラス型の変数を使う時も(一般の変数のように)変数宣言が必要である。宣言の仕方は基本型変数の宣言と同じである。

   型 変数名;

   例えば、Customerというクラス型の変数manを宣言するなら次のようにする。

   Customer man;

   これで、manとういCustomer型の変数を使う事が出来る。

インスタンス

   クラス型の変数は、C言語で言うところのポインタである。すなわちメモリの位置を示す値(アドレス)を記憶する。
  では、「クラス型の変数が記憶するのは、何のアドレスか」というと、インスタンスのアドレスである。

   インスタンスというのは、クラス型のデータの実体の事で、実際にメモリに割り当てたデータそのものの事である。
   クラスにはたくさんのメンバーを置く事が出来る。
  そのためクラス型のデータはクラスによって、小さいものから大きなものまでいろいろなサイズがある。
  たくさんのメンバーを持つ大きなデータもあるし、少ないメンバーを持つ小さなデータもある。
   そこで、javaではクラス型の変数にデータそのものを記憶するのではなく、ポインタを使う事にした。
  そして、実際のデータ(インスタンス)は、別のメモリのところに生成する事にした。クラス型の変数は、そのアドレスだけを記憶するのである。
   こうすれば、どんなクラス型の変数でも同じサイズにする事が出来る。
  (アドレスのサイズは決まっているので、ポインタのサイズは一定である。)

インスタンスの生成

   クラス型の変数を宣言しただけでは、ポインタが作られるだけで、その実体であるインスタンスは生成されない。

   Customer man; ・・・・・manというポインタが作られる

   インスタンスを生成するには、newを使う。

   new クラス名( )

   例えば、Customer型のインスタンスを生成するなら次のようにする。

   new Customer ( )

   newは指定された型のインスタンスを生成し、そのアドレスを返す。そこで、そのアドレスをそのクラス型の変数(ポインタ)で受取る。

   Customer man; ・・・・・・・・・・manというポインタを作り
   man = new Customer( ); ・・・インスタンスを生成してそのアドレスを代入する

   あるいは、この2つの文を1つにまとめても良い。

   Customer man = new Customer ( );

   これでmanがCustomer型のデータであるインスタンスを指すようになる。

フィールドはインスタンス固有

   Customer型のインスタンスは、2つのフィールドと2つのメソッドを持っている。

   class Customer {
    int id; ・・・・・・・・・・フィールド
    Syring name; ・・・・フィールド

    public void setData(int i, String n) { ・・・メソッド
     …
    }

    public void show( ) { ・・・・・・・・・・・・・・・メソッド
     …
    }
   }

   これらのフィールドに直接値を代入したり、メソッドを直接呼び出す事は出来ない。

   id = 100; ・・・・・×フィールドに代入
   show( ); ・・・・・・×メソッドを実行する

   それぞれのインスタンスは、固有のメンバーを持っている。例えば次のようにしてCustomer型のインスタンスを2つ生成したとする。

   Customer c1 = new Customer( );
   Customer c2 = new Customer( );

   たとえ名前は同じでも、c1の持つフィールドとc2の持つフィールドは異なる。
  例えば、顧客番号を記憶するフィールドidにしても、c1のidとc2のidは異なる。それゆえに、

   id = 100;

   のような代入をしようとしても、そのidがc1のものなのかc2のものなのか区別できない。

メンバーの参照

   生成したインスタンスのメンバー(フィールドやメソッド)を参照するには、どのインスタンスのメンバーなのかを指定する必要がある。
  そのためには、フィールドやメソッドの前にインスタンスの名前をつけて修飾する。このとき、インスタンス名とメンバーの間をピリオドで区切る。

   c1.id = 100; ・・・・・インスタンスc1のidフィールドに代入する
   c2.show( ); ・・・・・・インスタンスc2のメソッドを実行する

   以上をテストする為のサンプルは以下の通りである。

   サンプル:CustomerTest.java

   //
   //CustomerTest.java---クラスCustomerの利用例
   //
   class Customer {
    int id;      //顧客番号
    String name;  //名前

    public void setData(int i, String n) {
     id = i;
     name = n;
    }

    public void show( ) {
     System.out println("id =" + id);
     System.out.println("name =" + name);
    }
   }

   public class CustomerTest {
    public static void main(String[ ] args) {
     Customer c1 = new Customer( );
     c1.setData(1001, "宮本武蔵");
     c1.show( );
     System.out.println( );

     Customer c2 = new Customer( );
     c2.setData(1002, "佐々木小次郎");
     cs.show( );
    }
   }

   実行例

   $ java CustomerTest
   id = 1001
   namae = 宮本武蔵

   id = 1002
   name = 佐々木小次郎
   $ _

   このCustomerTest.javaには、2つのクラスが含まれている。
  1つは顧客を管理するクラスCustomerであり、1つはそのCustomerを利用するクラスCustomerTestである。

   class Customer {
    …
   }
   public class CustomerTest {
    …
   }

   クラスCustomerTestのmainメソッドでは、Customer型のインスタンスc1、c2を生成し、
  それぞれsetDataを呼び出してデータを設定し、showを呼び出して設定したデータを表示している。

   public static void main(String[ ] args) {
    Customer c1 = new Customer( ); ・・・・・・・・・インスタンスc1を生成
    c1.setData(1001, "宮本武蔵"); ・・・・・・・・・・・・c1にデータを設定
    c1.show( ); ・・・・・・・・・・・・・・・・・・・・・・・・・・・c1のデータを表示
    System.out.println8 );

    Customer c2 - new Customer( ); ・・・・・・・・・インスタンスc2を生成
    c2.setData(1002, "佐々木小次郎"); ・・・・・・・・c2にデータを設定
    c2.show( ); ・・・・・・・・・・・・・・・・・・・・・・・・・・・c2のデータを表示
   }

   なお、途中にSystem.out.println( );のように( )の中が空のprintlnを使っているが、これは改行する事を目的にしている。

次へ