クラスとインスタンス

<本章の目的>クラスとインスタンスに関する基本事項を理解する。クラスフィールドとクラスメソッドを習得する。

String クラス

String というクラスは、Java の java.lang というパッケージに含まれています。
java.lang パッケージに含まれているクラスはいつでも使えます。
String を java.lang.String と表記する場合もあります。
これは、java.lang というパッケージに含まれている String クラスという意味です。
パッケージについては「パッケージ」を参照して下さい。

オブジェクト

インスタンスのことを「オブジェクト」と呼ぶこともあります。
オブジェクトという用語は一般的に使われますが、
インスタンスという用語はクラスと対比して話すときに便利です。

クラスを宣言する

新たなクラスを作り出すことを「クラスを宣言する」といいます。
どうもJava言語では(この教科書では?)宣言と定義の境界が曖昧になっている感じがしますね。
メソッドの処理内容を記述することさえも宣言と呼んでしまうんですから。
Java言語ではクラスが基本単位だから、でしょうか?
C++言語でもクラスの定義という言葉はなかったように思いますしね。
あるいは、Java言語は純粋な宣言をすることが出来ないんじゃないでしょうか?

実引数と仮引数

実引数……メソッドを呼び出すときに与える引数
仮引数……メソッドの宣言に書かれた引数


this

this はインスタンス自身を表すものです。
this はインスタンスメソッドの中でしか使うことが出来ません。


名付けの慣習

クラス……大文字で始める
メソッド……小文字で始める
定数……すべて大文字


デフォルトコンストラクタ

デフォルトコンストラクタは次のように定義されています。

ClassName(){
  super();
}

フィールドの初期化

class Rectangle{
  int width=10;
  int height=20;
}

単にフィールドを初期化するだけなら、
コンストラクタの中でフィールドを設定しなくても、
フィールド宣言のところに初期値を書いておくだけでも大丈夫です。
C++言語ではこのような書き方は許されませんでした。
なぜなら、メンバー変数の宣言は定義ではなかったからです。
しかし、このように書けるのも便利でイイですね(笑)!

フィールドの初期値

boolean 型…… false
整数型…… 0
浮動小数点数型…… 0.0
参照型…… null

初期化されていない変数の値は未定義になります。
もっとも、変数は初期化しないとコンパイルエラーになり実行できませんが。

main メソッド

Java言語では、クラスを単なる部品としてではなく、1つのプログラムとして動かすことが出来ます。
そのとき、そのクラス内の main というメソッドが実行開始位置になります。
これまでに作ってきたクラスに main メソッドを追加すれば、そのクラス単体で動かすことが出来ます。

クラス型変数とインスタンス

ClassName cn=new ClassName();
cn.x= ……

cn ……クラス型変数であり、インスタンスを指すポインタ
new ClassName() ……インスタンスを作っています
cn.x ……変数 cn が指し示す先にあるインスタンスの x フィールド


スタックとヒープ

変数が確保されている領域をスタック( stack )と呼び、
またインスタンスが確保されている領域をヒープ( heap )と呼びます。

例題11-1 クラスフィールドとインスタンスフィールドの違いを確認して下さい。

○プログラム

class Rectangle{
  static int counter;
  int number;
  Rectangle(){
    number=counter++;
  }
}

public class ClassTest1{
  public static void main(String[] args){
    System.out.println("counter="+Rectangle.counter);
    Rectangle r1=new Rectangle();
    Rectangle r2=new Rectangle();
    Rectangle r3=new Rectangle();
    System.out.println("r1="+r1.number);
    System.out.println("r2="+r2.number);
    System.out.println("r3="+r3.number);
    System.out.println("counter="+Rectangle.counter);
  }
}


○実行結果

D:\atsushi\Java\List11-9>java ClassTest1
counter=0
r1=0
r2=1
r3=2
counter=3
-- Press any key to exit (Input "c" to continue) --

○解説

static という修飾子を付けてフィールドを宣言すると、クラスフィールドになります。
インスタンスフィールドはインスタンスごとに作られますが、
クラスフィールドはクラスごとに作られます(つまり1つ)。

インスタンスフィールド(インスタンス変数)はインスタンスの情報を保持しますが、
クラスフィールド(クラス変数)はクラスの情報を保持する、
すべてのインスタンスに共通のフィールドです。
クラスフィールドはインスタンスを作る前から存在しています。
C++言語の静的メンバー変数と一緒ですね。

クラスフィールドはインスタンスを作る前から使うことが出来ます。
クラスを通して呼び出すには……
Rectangle.counter
インスタンスを通して呼び出すには……
r1.counter
のように書きます。

例題11-2 クラスフィールドを返すクラスメソッドを作って下さい。

○プログラム

class Rectangle{
  static int counter;
  int number;
  Rectangle(){
    number=counter++;
  }
  static int getCounter(){
    return counter;
  }
}

public class ClassTest2{
  public static void main(String[] args){
    System.out.println("counter="+Rectangle.getCounter());
    Rectangle r1=new Rectangle();
    Rectangle r2=new Rectangle();
    Rectangle r3=new Rectangle();
    System.out.println("r1="+r1.number);
    System.out.println("r2="+r2.number);
    System.out.println("r3="+r3.number);
    System.out.println("counter="+Rectangle.getCounter());
  }
}


○実行結果

D:\atsushi\Java\List11-10>java ClassTest2
counter=0
r1=0
r2=1
r3=2
counter=3
-- Press any key to exit (Input "c" to continue) --

○解説

static を付けて宣言したメソッドはクラスメソッドと言います。
クラスメソッドは特定のインスタンスと関連付けられません。
したがって、クラスメソッドの中で「現在のインスタンス」を示す this を使うと、コンパイルエラーになります。
同様に、クラスメソッドの中で super を使っても、コンパイルエラーになります。

クラスメソッドはインスタンスを作る前から存在し、使うことが出来ます。
C++言語の静的メンバー関数と一緒ですね。

クラスメソッドだけのクラスを作ることも出来ます。
クラスメソッドだけを集めたクラスの目的は、インスタンスを作ることではなく、
関連したメソッドを1カ所にまとめ、プログラマが目的のメソッドを探しやすくすることです。

例題11-3 インスタンスフィールドを返すクラスメソッドを作って下さい。

○プログラム

class Rectangle{
  static int counter;
  int number;
  Rectangle(){
    number=counter++;
  }
  static int getNumber(Rectangle obj){
    return obj.number;
  }
}

public class ClassTest3{
  public static void main(String[] args){
    Rectangle r1=new Rectangle();
    Rectangle r2=new Rectangle();
    Rectangle r3=new Rectangle();
    System.out.println("r1="+Rectangle.getNumber(r1));
    System.out.println("r2="+Rectangle.getNumber(r2));
    System.out.println("r3="+Rectangle.getNumber(r3));
  }
}


○実行結果

D:\atsushi\Java\List11-13>java ClassTest3
r1=0
r2=1
r3=2
-- Press any key to exit (Input "c" to continue) --

○解説

仮引数にインスタンスを渡してもらうことで、
そのインスタンスのインスタンスフィールドを返すことが出来ます。
しかし、インスタンス無しでは使えないクラスメソッドなんて意味無いですけどね(汗)。

例題11-4 自分と他者のインスタンスの内容が等しいかどうかを調べるメソッドを作って下さい。

○プログラム

class Rectangle{
  int width;
  int height;
  Rectangle(int width,int height){
    this.width=width;
    this.height=height;
  }
  boolean equals(Rectangle r){
    if(r==null){
      return false;
    }else if(width==r.width && height==r.height){
      return true;
    }else{
      return false;
    }
  }
}

public class ClassTest4{
  public static void main(String[] args){
    Rectangle r1=new Rectangle(10,20);
    Rectangle r2=new Rectangle(10,30);
    Rectangle r3=new Rectangle(10,30);
    if(r1.equals(r2)){
      System.out.println("r1==r2");
    }else{
      System.out.println("r1!=r2");
    }
    if(r1.equals(r3)){
      System.out.println("r1==r3");
    }else{
      System.out.println("r1!=r3");
    }
    if(r2.equals(r3)){
      System.out.println("r2==r3");
    }else{
      System.out.println("r2!=r3");
    }
  }
}


○実行結果

D:\atsushi\Java\ListA11-4>java ClassTest4
r1!=r2
r1!=r3
r2==r3
-- Press any key to exit (Input "c" to continue) --

○解説

比較対象は必ず存在しているはずなので、
2つのオブジェクトを引数として渡してもらうより、
1つのオブジェクトを引数として渡してもらい、自分と比較した方がスマートですよね。

public の意味

public static void main(String[] args){
  ……
}

ここで使われている public という修飾子は、「パッケージの外から呼び出せる」という意味です。
パッケージについては「パッケージ」をご覧下さい。
public については「スーパークラスとサブクラス」もご覧下さい。

修飾子

final
 最終的なものであり、もう変更できないことを表す。
 クラスやインタフェースなら拡張できないことを表す。
 インスタンスフィールドやクラスフィールなら定数であることを表す。
 メソッドなら上書き定義(オーバーライド)することを禁止する。

abstract
 抽象クラスや抽象メソッドであることを表す。
 メソッドには付けられますが、フィールドには付けることは出来ません。
 詳しくは「スーパークラスとサブクラス」を参照して下さい。

static
 クラスフィールドやクラスメソッドであることを表す。

synchronized
 synchronized メソッドであることを表す(「スレッド」参照)。

native
 Java言語以外の言語(C言語やC++言語)で書かれたメソッド(ネイティブメソッド)であることを表す。

public / protected / private
 アクセス制御を行います。
 アクセス制御については「スーパークラスとサブクラス」を参照して下さい。

toString メソッド

インスタンスが文字列として扱われるとき、toString メソッドが自動的に呼び出されます。

toString メソッドと equals メソッド

toString メソッドは、クラス階層の最上位である Object クラスで実装されており、
すべてのクラスに継承されています。
このため、全てのクラスが潜在的には toString メソッドを持っていることになります。
自分で toString を実装するということは、
既に持っている toString を上書き(オーバーライド)することになります。
また、Object クラスは他のオブジェクトとの同一性を調べる equals メソッドを持っています。
これによって、すべてのオブジェクトは他のオブジェクトとの同一性を調べることが出来ます。


戻る / ホーム