クラスの作成
部品としてのクラス
今までのサンプルプログラムでは、JavaAPIに含まれるStringクラスやMathクラスといったクラスを利用するという観点からクラスを見てきましたが、Javaではこうしたクラスをユーザ自身が定義、作成して利用することができます。StringクラスやMathクラスなどは、プログラムの中で「部品」として使われることを前提に、便利なフィールドやメソッドを備えていて、とても機能的に設計されていました.今まで作成してきたプログラムも「クラス」の一種ではありますが、こちらは「アプリケーション」として動作させることを前提に作られたもので、「部品」として使うのには向いていません。「部品」として機能する「クラス」を作成するには、はじめからそのことを念頭において設計する必要があります。
クラスの構造
以前、「Javaにはフィールドとメソッドというものが含まれる」ということを説明しましたが、新しいクラスを自作するときには、作成するクラスにどのようなフィールド、どのようなメソッドを持たせてやるかをしっかり設計することが重要なポイントになります。
Javaのクラスは、一般的には次のような要素から構成されます。
要素 説明
クラスの宣言 クラスの名前や継承関係を宣言する部分
フィールド(変数) クラスの持つ情報を保存する領域
メソッド クラスの持つ機能を定義する部分
コンストラクタ クラスのインスタンスを作成するための特別なメソッド
フィールドだけを持つクラス
Javaのクラスにはクラス宣言のほかに、フィールド、メソッド、コンストラクタの3つの要素が含まれていますが、ここではそのうちのフィールドについて説明します。
フィールドとはクラスの持つ情報を確保しておくための領域で、具体的にはクラス宣言の後すぐに変数または定数の形で定義されます。通常はこのフィールドの定義の後に、メソッドやコンストラクタの定義が続きます。
class Circle{
   //フィールドの定義
   double x;  //円のX座標
   double y;  //円のY座標
   double r;  //円の半径
}

class Lesson15{
   public static void main(String args[]){
      //Circleクラスのインスタンスを作成
      Circle A = new Circle();

      //Circleクラスのフィールドに値を代入
      A.x = 3;
      A.y = 4.5;
      A.r = 1;

      //各フィールドの値をコンソール上に表示
      System.out.println("円AのX座標は" + A.x +"です");
      System.out.println("円AのY座標は" + A.y +"です");
      System.out.println("円Aの半径は" + A.r +"です");     
   }
}
このプログラムを実行すると次のようになります
円AのX座標は3です
円AのY座標は4.5です
円Aの半径は1です

(解説)

ここで作成しているCircleクラスは2次元空間における円の持つ情報である、「円のX座標」、「円のY座標」、「円の半径の長さ」を管理するクラスです。これらの情報を保存しておくための領域がフィールドで、ソースコード中では「x」「y」「r」がそれに当たります。宣言の仕方は通常の変数の場合と同じ形式です。(3行目から5行目)
次にLesson15のプログラムを見ていきましょう。このプログラムは、Circleクラスのテスト用に作られたアプリケーションです。Circleクラスのような自作クラスは、これまでに利用してきたStringクラスのようにクラスのインスタンスを作成したり、フィールドを参照したり、メソッドを呼び出したりすることができます。

@インスタンスの作成
Circleクラスのインスタンスを作成しているのは次の部分です。
Circle A = new Circle( );
「Circle A」の部分でCircle型のオブジェクト変数を宣言し、「new Circle()」でCircleクラスの新しいインスタンスを作成し、中央の「=」で左辺の変数に代入してます。

Aフィールドに値を代入
フィールドの値にアクセスするには、オブジェクト名とフィールド名を .(ドット)で繋いでやります。Circle型の変数Aのxフィールドに値を代入する場合は次のように行います。
A.x = 3;
Bフィールドの値を参照
フィールドの値の参照も、やはり同じ要領で行うことができます。
 戻り値の無いメソッドの定義
前回のプログラムではフィールドのみを持つクラスを作成しましたが、今回はこれを少し改良して、フィールドとメソッドを持つクラスを作成しています。フィールドはクラスの持つ情報を保存しておく領域でしたが、これに対して、メソッドはクラスの持つ特技(動作)のようなものだと言うことができます。
今までのプログラムではMathクラスやStringクラスのもつさまざまなメソッドを利用してきましたが、自作クラスにもああいったメソッドを独自に定義することができます。
class Circle{
   //フィールドの定義
   double x;  //円のX座標
   double y;  //円のY座標
   double r;  //円の半径

   //メソッドの定義
   void show(){
      //各フィールドの値をコンソール上に表示
      System.out.println("円のX座標は" + A.x +"です");
      System.out.println("円のY座標は" + A.y +"です");
      System.out.println("円の半径は" + A.r +"です");    
   }
}

class Lesson16{
   public static void main(String args[]){
      //Circleクラスのインスタンスを作成
      Circle A = new Circle();

      //Circleクラスのフィールドに値を代入
      A.x = 3;
      A.y = 4.5;
      A.r = 1;

      //showメソッドを呼び出す
      A.show();
   }
}
このプログラムを実行すると次のようになります
円のX座標は3です
円のY座標は4.5です
円の半径は1です

(解説)

戻り値の無いメソッドの定義

クラス内でメソッドを定義するには次のような書式を使います。
 void メソッド名(型名 引数 ) {
  このメソッドに行わせたい処理の内容
 }

メソッド名の前についているvoidというのは、「空の」とか「何もない」といった意味を持つ言葉です。戻り値の内メソッドを定義する際には、メソッド名の前にこのvoidをつける決まりになっています。
「メソッド名」の部分には、このメソッドにつけたい名前を指定します。
メソッド名の後ろには、このメソッドに与える引数を( )で囲んで記述します。複数の引数を与えたい場合は、
void メソッド名 ( 型名 引数1, 型名 引数2,…)
という具合に、カンマで区切りながら順に並べます。それぞれの引数の型は異なっていてもよく、たとえば、1番目の引数はString型、2番目の引数はint型…というように定義することも可能です。逆に引数を一つも指定しない場合、()の中には何も記述する必要はありません。
 void メソッド名(){  }
とし、{}の中にメソッドに行わせたい処理の内容を記述します。

メソッドを呼び出す
自作クラス内で定義されたメソッドの呼び出し方法も、Stringクラスのもつメソッドを呼び出す場合と同様です。今回のshowメソッドであれば次のように呼び出します。
A.show();
なお、showメソッドはクラスのインスタンスに関連付けられた「インスタンスメソッド」なので、メソッドを呼び出す前に,new演算子を使ってインスタンスの作成を行っておく必要があります。
メソッドの戻り値について
戻り値というのはメソッドを実行した結果、返される値のことです。
以前のサンプルプログラムで、StringクラスのlengthメソッドというものをつかってStringクラス型のオブジェクトに代入されている文字列の「文字数」がint型の値としてえられました。このようにして戻される値が戻り値で、この場合「戻り値の型はint型である」と言います。
今回のサンプルプログラムで定義しているメソッドの主な動作は、各フィールドである「円のX座標、Y座標、半径」をコンソール上に表示するというものです。このメソッドは実行することによって何らかの値が返されるという性質のものではなく、単に「動作」だけを行います。
これが「戻り値のないメソッド」で、このようなメソッドを定義する際にはキーワード「void」をメソッドの頭につけることになっています。
 戻り値のあるメソッドの定義
class Circle{
   //フィールドの定義
   double x;  //円のX座標
   double y;  //円のY座標
   double r;  //円の半径

   //メソッドの定義
   void show(){
      //各フィールドの値をコンソール上に表示
      System.out.println("円のX座標は" + A.x +"です");
      System.out.println("円のY座標は" + A.y +"です");
      System.out.println("円の半径は" + A.r +"です");
      System.out.println("円の面積は" + calcArea());    
   }

   //面積を計算するメソッドの定義
   double calcArea(){
      double S = Math.pow(r,2)*Math.PI;
      return S;
   }
}

class Lesson17{
   public static void main(String args[]){
      //Circleクラスのインスタンスを作成
      Circle A = new Circle();

      //Circleクラスのフィールドに値を代入
      A.x = 3;
      A.y = 4.5;
      A.r = 1;

      //showメソッドを呼び出す
      A.show();
   }
}
このプログラムを実行すると次のようになります
円のX座標は3です
円のY座標は4.5です
円の半径は1です
円の面積は3.14…です

(解説)

今回のサンプルプログラムは、Lesson16で定義した戻り値の無いメソッド(show)のほかに,double型の戻り値を持つ円の面積を計算するメソッドを定義しています。戻り値のあるメソッドを定義する際には次の書式を使います。
 戻り値の型名 メソッド名 (型名 引数名){
   処理の内容;
   return 戻り値;
 }

戻り値の無いメソッドの定義方法と異なるのは次の2点です。
@メソッド名の前に、戻り値の型を記述する
Areturnキーワードを用いて、戻り値として返す値を指定する。
returnは、文字通り「戻す」とか「返す」と言う意味で,メソッド内で処理を行った結果取得した値を戻り値として「返す」働きをします。つまり、return文の後に記述された値が、このメソッドの戻り値になるわけです。なお、return文に続けて記述された変数や式の値は、メソッド名の前に記述した戻り値の型名と同じでなくてはなりません。

このサンプルプログラムでは、まず、面積を入れるための変数を宣言(double S)し、Mathクラスのフィールドとメソッドをつかって、面積を計算し、宣言した変数Sに代入しています。そして、return文で面積を戻り値として返しています。

※Mathクラスのpowメソッドは以下のような書式で使用します。
  Math.pow ( 3 , 2 )
これで3の2乗を求めることができます。

同じクラスのメソッド内からメソッドを呼び出す
定義したメソッドは、同じクラス内から呼び出して使うことが可能です。今回のプログラムでは、showメソッドの中で,calcAreaメソッドを呼び出しています。このように同じクラスの内部から呼び出す場合,メソッド名の前にオブジェクト名や、クラス名を記述する必要はありません。
コンストラクタの定義 
ここでは、クラスのインスタンスを作成するための特殊なメソッド「コンストラクタ」の概要,およびその定義方法について説明します。
Javaのクラスはコンストラクタと呼ばれる特殊なメソッドを持つことができます。コンストラクタとは、簡単に言えばクラスのインスタンスを作成するために用いるメソッドです。
クラスのインスタンスを作成して利用するためには、通常そのクラスを初期化するための処理が必要になります。たとえば,前回作成したサンプルプログラムのCircleクラスでいえば、「x , y , r の3つのフィールドに値を入れる。」という処理が必要でした。これらのフィールドに何らかの値が入っていないことには、showメソッドやcalcAreaメソッドを呼び出す意味がありません。
「クラスのインスタンスを利用する際必ず必要となる処理」は、インスタンスを作成した時点で自動的に行っておくのが合理的です。これを行うのが、すなわちコンストラクタの仕事なのです。
class Circle{
   //フィールドの定義
   double x;  //円のX座標
   double y;  //円のY座標
   double r;  //円の半径

   //コンストラクタの定義
   Circle(double x_zahyou, double y_zahyou, double hankei) {
       //各フィールドに値を代入
       x = x_zahyou;
       y = y_zahyou;
       r = hankei;
   }

   //メソッドの定義
   void show(){
      //各フィールドの値をコンソール上に表示
      System.out.println("円のX座標は" + A.x +"です");
      System.out.println("円のY座標は" + A.y +"です");
      System.out.println("円の半径は" + A.r +"です");
      System.out.println("円の面積は" + calcArea());    
   }

   //面積を計算するメソッドの定義
   double calcArea(){
      double S = Math.pow(r,2)*Math.PI;
      return S;
   }
}

class Lesson18{
   public static void main(String args[]){
      //Circleクラスのインスタンスを作成
      Circle A = new Circle( 3 , 4.5 , 1);

      //showメソッドを呼び出す
      A.show();
   }
}
このプログラムを実行すると次のようになります
円のX座標は3です
円のY座標は4.5です
円の半径は1です
円の面積は3.14…です

(解説)

コンストラクタは次のようにして定義します。
クラス名(型名 引数名){
  インスタンス作成時に行いたい処理

メソッドの定義形式とよく似ていますが,宣言文の前に型名や、voidなどのキーワードはつきません。また、メソッドの場合は好きな名前を自由に定義することができましたが,コンストラクタの場合は必ずクラス名と同じ名前になっている必要があります
クラス名の後ろに続く()の中には、コンストラクタ内で定義されている処理を実行するために必要な引数を記述します。引数が不要な場合は空のカッコのみを記述し,複数の引数が必要な場合は引数名をカンマで区切りながら順に並べていきます。
コンストラクタの内部では,x , y , r の各フィールドに値を代入する処理を行っています。各フィールドには、コンストラクタの引数として呼び出し元から受け取ったx_zahyou , y_zahyou , hankei という値をそれぞれ代入しています。

★デフォルトのコンストラクタ★
クラスを作成する際に,明示的にコンストラクタを定義しないと,そのクラスには次のような構造を持つデフォルトのコンストラクタがコンパイラによって自動的に作成されます。
 クラス名(){
 }

デフォルトのコンストラクタは引数は一つも持たず、変数の初期化などの処理を行うためのコードも含みません。純粋にインスタンスの作成だけを行う働きをするのです.

コンストラクタの呼び出し
これまでのプログラムでは、クラスのインスタンスを作成する際には,次のような書式を用いていました。
 new クラス名();
今までは、これが「クラスのインスタンスを作成するための呪文のようなもの」であるという具合に考えてもらっていましたが、実はこの「クラス名()」の部分では、そのクラスのコンストラクタを呼び出していたのです。
今回のサンプルプログラムでは、次のようにCircleクラスのインスタンスを行っています。
 Circle A = new Circle( 3 , 4.5 , 1 );
Circleクラスのコンストラクタには、先ほど見てきたように、x_zahyou , y_zahyou , hankeiの3つの引数が定義されていました。ここの呼び出しにも、きちんとその3つの引数が指定されているのがわかります。
 コンストラクタのオーバーロード
class Circle{
   //フィールドの定義
   double x;  //円のX座標
   double y;  //円のY座標
   double r;  //円の半径

   //コンストラクタの定義
   Circle(double x_zahyou, double y_zahyou, double hankei) {
       //各フィールドに値を代入
       x = x_zahyou;
       y = y_zahyou;
       r = hankei;
   }
   Circle(double x_zahyou, double y_zahyou) {
       //各フィールドに値を代入
       x = x_zahyou;
       y = y_zahyou;
       r = 1;
   }
   Circle(double hankei) {
       //各フィールドに値を代入
       x = 0;
       y = 0;
       r = hankei;
   }

}
今回のサンプルプログラムでは、コンストラクタを複数定義しています。
1つ目のコンストラクタでは、「X座標」、「Y座標」、「円の半径」という3つの引数をとります。
2つ目のコンストラクタでは、「X座標」、「Y座標」の二つの引数を取り,円の半径は1にします。
3つ目のコンストラクタでは、「円の半径」を引数に取り、円の中心の座標は原点にします。
このように、コンストラクタは複数定義することができますが、引数のリストがまったく同じコンストラクタを重複して定義することはできないので,各コンストラクタに与える引数の方や個数を変えてやる必要があります。これをコンストラクタのオーバーロードと言います。
特定のクラスから何通りもオブジェクトを作成できるので、コンストラクタのオーバーロードはJavaプログラムでよく使われます。
クラスフィールドとクラスメソッド
今まで作成してきたCircleクラスに含まれるフィールドとメソッドはCircleクラスのオブジェクトに直接関連付けられているフィールドとメソッドなので、それぞれ、インスタンスフィールドとインスタンスメソッドに当たります。
ここでは、サンプルプログラムを通して、オブジェクトを作成せずに使用することのできるクラスフィールドとクラスメソッドの定義の方法について説明していきます。
class calculator{
   //クラスフィールドの定義
   static double pai = Math.PI;

   //クラスメソッドの定義
   static int add(int a, int b){
       return a + b;
   }
}

class Lesson19{
   public static void main(String args[]){
      System.out.println("円周率="+calculator.pai);
      System.out.println("2+2="+calculator.add(2,2));
   }
}
クラスフィールドとは、そのクラスすべてのオブジェクトから共有される変数です。つまり、クラスそのものに結びついている変数です。
クラスフィールドを宣言するには次のように行います。
 static 型名 変数名;
このようにstaticというキーワードを付加します。

同様に、クラスメソッドを宣言するときもstaticキーワードを付加するだけです。
 static 戻り値の型名 メソッド名(引数){

 }

引数は無ければ省略できます。

このサンプルプログラムでは、calculatorクラスのクラスフィールドとして円周率πをもち、クラスメソッドとして、足し算メソッドを持っています。
クラスフィールドは「クラス名.フィールド名」で呼び出されます。
同様に、クラスメソッドは「クラス名.メソッド名」という形で呼び出されます。
このプログラムを実行すると次のようになります
円周率=3.1415…
2+2=4
※staticキーワードを使ってメソッドを宣言する(すべてのアプリケーションのmainメソッドを含む)と、そのメソッドからは他のstaticメソッドしか呼び出すことができず、クラスフィールドにしかアクセスすることができません。また、このメソッドではthisキーワードとsuperキーワードを使うこともできません。(詳細については後ほど説明します。)
それでは、mainメソッドから非staticメソッドを呼び出すにはどうしたらいいのでしょうか?このためには、これまで見てきたように、mainメソッド内で他のクラスのオブジェクトを作成し、そのオブジェクトのメソッドを呼び出します。
メソッドのオーバーロード 
class calculator{
   //クラスメソッドの定義
   static int add(int a, int b){
       return a + b;
   }
   //addメソッドのオーバーロード
   static int add(int a, int b, int c){
       return a + b + c;
   }
}

class Lesson20{
  public static void main(String args[]){
    System.out.println("1+2+3="+calculator.add(1,2,3));
    System.out.println("2+2="+calculator.add(2,2));
   }
}
コンストラクタと同様に、メソッドをオーバーロードすることもできます。メソッドのオーバーロードとは、名前が同じで引数が異なるメソッドが複数あることです.
メソッドをオーバーロードするには、そのメソッドを単に複数回定義すればいいです。ただし、引数は毎回変える必要があります。
このサンプルプログラムでは、calculatorクラスのaddメソッドをオーバーロードしています。int型の引数が2つの場合のaddメソッドと、int型の引数が3つの場合のaddメソッドを定義しています。

このように、オーバーロードは強力なテクニックです。さまざまな種類の引数のリスト(パラメーターリスト)をすべて1つのメソッドに渡すことができるので、コード内でそのメソッドをさまざまな方法で簡単に使用することができます。
このプログラムを実行すると次のようになります
1+2+3=6
2+2=4
アクセス制御
クラスのすべてのフィールドとメソッドは、それが定義されているクラス本体のなかで必ず使用できます。しかしJavaは、クラスのフィールドがクラスの外部で使われないように、アクセス制御規則を定義しています。既に示したいくつかの例では、フィールドやメソッドの宣言の中で、public修飾子を使っています(mainメソッドなど)。このpublicキーワードとprotectedおよび、privateは、アクセス制御修飾子です。これらは、フィールドまたはメソッドに対するアクセス規則を指定します。

publicを使ってフィールドやメソッドを宣言すると、そのフィールドやメソッドにはプログラム内のどこからでもアクセスできるようになります。

privateを使って宣言すると、そのフィールドやメソッドはそのクラス内からしかアクセスできません。

protectedを使って宣言すると、そのクラスと、同じパッケージ内のほかのクラス、そのクラスから派生したクラスからアクセスできます。

アクセス制御修飾子を指定しない場合、デフォルト値として、そのクラス、同じパッケージ内でそのクラスから派生したクラス、同じパッケージ内のほかのクラスからアクセスできます。

場所 private アクセス制御修飾子なし protected public
同じクラス
同じパッケージ内のサブクラス
同じパッケージ内の非サブクラス
他のパッケージ内のサブクラス
他のパッケージ内の非サブクラス
class printer{
   public void print(){
       hello();
   }
   private void hello(){
       System.out.println("Hello from Java!");
   }
}

class Lesson20{
  public static void main(String args[]){
     printer A = new printer();
     A.print();
   }
}
printerクラスのprintメソッドを呼び出すと、このクラスの外からは呼び出すことのできないhelloメソッドを呼び出すことができます。
privateまたはprotectedを使ってメソッドを宣言すると、コードの残りの部分からそのメソッドへのアクセスが制限でき、制御が行き届くので、通常はよいことです。
このプログラムを実行すると次のようになります
Hello from Java!