クラスと継承

  1. クラスとオブジェクト

    1. クラスとは
      クラスは何らかの「モノ」を表現するもので、言語Cの構造体を拡張したものと考えることもできます。クラスでは変数だけでなくメソッド(関数)も内部に定義できます。
      クラスは次のように定義します。クラス内部で宣言された要素(変数およびメソッド)をメンバーと呼びます。

       class クラス名{ クラスのメンバ,..... }

      で定義します。クラスは1種の型宣言で、実行に必要なメモリ領域(クラスのインスタンス:実体)は確保されません。

       クラス名 名前 = new クラス名();

      で、クラスに対応する「実体」を宣言できます。この「実体」をクラスのインスタンスと呼びます(オブジェクトと呼ぶこともあります)。new によりクラスの型に対応した領域が割り当てられます。これがインスタンスの「実体(インスタンス)」です。

       名前.メンバ

      で、クラスのメンバー(変数やメソッド)を指定できます。

    2. 変数のみのクラス
       最初に変数のみから構成されるクラスを紹介します。文字列 name と整数 age から構成されるクラス man を定義します(これは、C言語の「構造体」に相当します)。クラスmantest クラスの main() で、クラスMan のインスタンス m1 と m2 を作成し、name と age に値を設定し、表示します。これは、C言語の struct に相当します。
      class Man{
        String name;
        int age;
      }
      
      public class mantest{
        public static void main(String args[]){
          Man m1=new Man();
          m1.age=20;
          m1.name="abe";
          System.out.println(m1.name+":"+m1.age);
      
          Man m2=new Man();
          m2.age=16;
          m2.name="sasaki";
          System.out.println(m2.name+":"+m2.age);
        }
      }
      実行結果
      abe:20
      
      sasaki:16

    3. メソッドを含むクラスとコンストラクタ
       クラスにはメソッドも定義できます。クラス名と同じ名前で型指定のないメソッドを定義することができます。このメソッドはコンストラクタと呼ばれ、new でクラスからインスタンスを生成するときに、自動的に呼び出されます。コンストラクタにも引数を設定できます。
       引数の違いで複数のコンストラクタを用意できます。new に引数を指定すると対応する引数をもつコンストラクタが実行されます。

      1. 例1
        コンストラクタ、および、setAge、isYoung()、メソッドを定義したクラス Man2 を定義します。new Man2() で、コンストラクタを呼び出し、名前を指定します。また、getName()は名前を返すメソッド、isYung は age が18以下のとき true を返すメソッドです。
        class Man2{
          private String name;
          private int age;
        
          Man2(String nm){//コンストラクタ
            name=nm;
          }
        
          public void setAge(int ag){
            age=ag;
          }
        
          public boolean isYoung(){
            return age<18;
          }
        
          public String getName(){
            return name;
          }
        }
        
        public class mantest2{
          public static void main(String args[]){
           Man2 m2=new Man2("abe");//コンストラクタを呼び出す
           m2.setAge(20);
           System.out.println(m2.getName()+":"+m2.isYoung());
          }
        }

      2. 例2 引数付きコンストラクタ
        Circleは位置と半径:rから構成されるものとします。

        public class Circle{
         public double x,y,r;
         public Circle( double x,double y,double r)//コンストラクタ
         { this.x = x; this.y = y; this.r = r ;}

        このCircleのインスタンスは次のように生成できます。

        Circle c1;
        c1=new Circle(100,200,20);

  2. クラスとstatic修飾子

    1. static宣言された変数
       クラスのインスタンスは一般に new により実行時に動的に生成されます。クラスで宣言された各変数は、インスタンス毎に別の変数として扱われます。
       これに対し、static 宣言された変数は、予め「静的」にメモリ領域が割り当てられています。したがって、staticが指定された変数はクラスに共通の変数となります。
       この変数は クラス名.変数名 で参照できます。また、クラスのインスタンスを通しても参照できますが、この場合、クラス名.変数名 として利用できます。staticで宣言された変数は、クラスで共通の(唯一の)変数になりますから、クラス変数とも呼ばれます。

      1. 例1
        次の例では Count がstaticで宣言されています。これは、newでインスタンスを生成するたびに

         Man3.Count++;

        で、1加えられます。この変数は m4.Count++ でも参照できますが、Man3.Count++; と同じ意味です。誤解されやすいので、クラス名.変数名 として利用するほうが良いでしょう。

        class Man3{
          static int Count=0;
          String name;
          int age;
          Man3(String nm){
            name=nm;
          }
        
          public void setAge(int ag){
            age=ag;
          }
        
          public boolean isYoung(){
            return age<18;
          }
        }
        
        public class mantest3{
          public static void main(String args[]){
           Man3 m3=new Man3("abe");
           Man3.Count++;
           Man3 m4=new Man3("ido");
           m4.Count++;//Man3.Count++と同じ
        
           System.out.println("static count:"+Man3.Count);
          }
        }

    2. static宣言されたメソッド
       staticキーワードを付加して定義されたメソッドはクラスメソッドと呼ばれます。クラスメソッドは静的に生成されるので、newでインスタンスを生成することなく、クラス名とメソッドの名前を指定して直接呼び出すことができます。

      1. 例1
        プログラムを実行開始するにはmain()メソッドが必要です。main()には static 宣言が必要です。
        public class app1{
          public static void main( String[] args)  { 
             System.out.println("at a:"+a.common +":"+ a.local);  }
         }

      2. 例2
         static宣言されたメソッドは、別のクラスのstatic宣言された関数を呼び出すことができます。

        class calc{
            static int add(int op1,int op2){ 
              return op1+op2;
            } //クラスメソッド
        }
          
        public class app1{
            public static void main( String[] args){ 
               System.out.println(calc.add(2,3));
            }
        }
        この例で、main()、System.out.println()、もクラスメソッドです。

      3. 例3 Mathクラス
        多くの数学関数はJava.lang.Mathクラスでクラスメソッドとして定義されています。利用するときには、クラス名 Math を指定します。

         d1=Math.cos(0.1);
         d2=Math.pow(2.3,4.0);

    3. thisキーワードとクラスの配列
      1. クラスの配列を利用
         クラスの配列を利用するには、配列の要素に予めインスタンスを作成しておく必要があります。次の例では、「座標」を記憶する Point 型の配列を利用する例です。pt[i]=new Point(0,0); で配列の要素にクラスのインスタンスを作成しておきます。これをしないで、いきなり、pt[kaisu].x のように 配列の要素を利用すると、実行時にエラーになります。

        Point pt[];
        pt=new Point[20];

        for(int i=0;i<20;i++) pt[i]=new Point(0,0); //Pointを生成する
        //利用
        pt[kaisu].x=bx; pt[kaisu].y=by; if(kaisu<19) kaisu++;

      1. thisキーワード
         自分自身のクラスを参照したい場合 this を利用します。クラス内部で定義された変数 x やメソッド f() の参照は、this.x や this.f() の省略形と考えることができます

    4. アクセス指定子と有効範囲
       クラス、変数、メソッドにはアクセス指定を付加することにより、異なるクラスからのアクセスを制限できます。他のクラスからは public が付加されている変数やメソッドのみが利用できます。privateを指定すると、クラス外部からはアクセスできません。pretectedを指定をすると、同じパッケージ(後で説明します)のサブクラスまで利用可能です。無指定の場合は、同じパッケージであれば利用できます。パッケージは次のページで説明します。

    5. 領域の開放とガベージコレクション

      1. ガベージコレクション
        Javaでは new で領域を確保しますが、確保した領域の開放は自動的に行われます。システムは参照されなくなった領域をチェックし、自動的に開放します。この処理をガベージ(ごみ)コレクション(収集)とよびます。大きなサイズの領域を処理中に開放したい場合は、その参照変数の値をnullにします。nullになった領域は次のガベージコレクションのときに回収されます。

      2. 循環参照
        お互いに参照しあうと、双方が終了するまで、両者の領域は開放されないためメモリが解放されません。例えば、クラスaのコンストラクタでbを生成し、また、クラスbのコンストラクタでaを生成すると、無限の循環参照となりメモリ領域を食いつぶしてエラーになります。

      3. 実行速度
        ガベージコレクションはプログラムを楽にしますが、処理時間を長くする要因にもなります。たとえば、newやそれを行ったメソッドの終了はメモリ領域の管理を伴い、大量のメモリの確保と収集(ガベージコレクション)は処理時間を長くする要因になります。
         メモリの管理を伴わない static な変数やメソッドの処理時間は、Cのプログラムと比較して遜色がありません。しかし、メモリ管理を伴う処理は最悪の場合、Cのプログラムと比較して数倍の処理時間を要することがあります。
         一方、自動開放をしないCのプログラムでは、開放(relaese)を伴わないでnewを行う関数を繰り返し実行するとメモリ不足(stackOverFlow)の実行時エラーとなります。この種のエラーを発見するのは、困難な作業になります。

  3. クラスの継承

    1. 継承

      1. extend
        あるクラスのメソッドや変数を継承(extend)したクラスを定義できます。そのクラスでは継承したクラスのメソッドや変数をデフォルトとして利用することができます。一般的なクラスを作成し、さらにそれを特殊化(専門化)したクラスを定義するときに利用します。Javaでは一つのクラスしか継承できません。

      2. アクセス指定子
        アクセス指定子を指定すると継承に制限を加えることができます。accses指定子には、private、指定しない、protected、public、の4種です。

    2. オーバーライド

      1. オーバーライド
        継承したクラスに含まれるメソッドを継承したクラスで定義し直すことが出来ます。これをメソッドのオーバーライドと言います。(同じクラス、同じ名前だが引数や戻りの型が異なるメソッドを定義するのが、オーバーロードです。)

      2. final
        継承したメソッドでは、親のメソッドを書き直すことでオーバーライドできます。これが望ましくない場合、メソッドに final を付加して、オーバーライドを禁止することができます。

    3. 継承とコンストラクタ、superメソッド

      1. 継承したクラスのコンストラクタ
        クラス b が a を継承している場合、b のオブジェクトを生成するとき a のデフォルトのコンストラクタ(引数なし)が最初に呼び出されます。

      2. super()メソッド
        デフォルトでない、引数つきのコンストラクタを呼び出すには、super(引数)メソッドを利用します。super(引数)は明示的に引数に対応する親クラスのコンストラクタを呼び出すメソッドです。

      3. 多態性
        クラス b がクラス a を継承しており、a1,b1 を a,b のオブジェクト、aref を a の参照とします。a,b がメソッドplayを定義している場合、aref.playは、代入されるオブジェクトで異なるメソッドを呼び出すことができます。これを、多態性と呼びます。aref.playで呼び出すメソッドはコンパイル時には一意でなく、実行時に定まることになります。
         詳細はこちらを参照して下さい。

         aref=a1
         aref.play(); //クラスaのプレイ
         aref=b1;
         aref.play(); //クラスbのプレイ

    4. 抽象クラスとabstract

       
      1. 抽象クラス
         抽象クラスは抽象度の高いオブジェクトを表現する場合に便利なクラスです。宣言だけを持ち、定義はそれを継承したクラスに任せるメソッドを定義できます。このようなクラスを抽象クラスといいます。

      2. abstract
        定義を持たないメソッドは abstract として宣言します。abstractクラスを継承した場合、メソッドを定義しないとインスタンスにできません。

      3.  Coinクラス
         Coinクラスは硬貨を代表しますが、種類が決定しないと、額が決定しません。そこで、value() メソッドは abstractとし、派生クラスで、額を決定します。
        // 抽象クラス: 硬貨
        class Coin{
            public abstract int value();
          public String material="metal";
        }
        
        // 1円硬貨
        class Coin1 extends Coin{
            public int value(){
                return 1;
            }
        }
        
        // 10円硬貨
        class Coin10 extends Coin{
            public int value(){
                return 10;
            }
        }

    5. interface
      メソッドの宣言や定数のみを集めて interface を宣言することが出来ます。メソッドの作成(インプリメント)を要請する場合、メソッドの形式を統一したり、各種定数を渡すときに便利な機能です。

      1. interfaceの定義
        classの替わりに、キーワードinterfaceで宣言します。型のみを定義するメソッドにはabstractを付記します。

        public interface Rating{
         public abstract int rating();
         ..
        }

      2. implements:インターフェースの利用
        インターフェースを利用するには、implements キーワードを利用します。implements をする場合、interface内部のすべてのメソッドを定義する必要があります。
         Javaでは複数のクラスを継承することはできませんが、複数のinterfaceをimplementsすることは可能です。
        インターフェースの宣言で、extends は可能ですが、implements の宣言はできません。

  4. よく利用されるクラス
    1. API
      理由できるメソッドはAPI(Application Interface)として、参照できます。特に、SUN社がHPで提供するマニュアルは充実しています。
       http://java.sun.com/j2se/1.4/ja/docs/ja/api/



      クラス名がわかれば、左下のクラスからクラスで定義されている定数やメソッドが参照できます。メソッド名がわかっている場合、索引から参照できます。

    2. クラスメソッドを知る
      Jbuilderなどを利用すれば、クラス名がわかれば、静的メソッドならクラス名、インスタンスメソッドならそのクラス名のインスタンスに"."を指定すれば、メソッドの一覧が表示されます。

    3. ラップクラス
      int、booleanなどのクラスをもたない各基本型にもこれらを定義するクラス(ラップクラスと呼ばれます)が定義されています。例えば、intのラップクラスである Integer クラスには文字から int に変換する static なメソッドParseInt(String s)や、数字を文字に変換するインスタンスメソッド toString() が定義されています。他に、Character、Byte、Short、Long、Float、Doubleクラスが定義されています。

    4. String、StringBufferクラス
      Stringクラスは文字列の生成、読み出し、切り出しができます。
      Stringの編集を行います。追加、挿入、文字変更ができます。

    5. Mathクラス
      各種の数学関数を利用できます。すべて静的メソッドでクラス名から呼び出しができます。

    6. Systemクラス
      void exit(int code); プログラムを終了します
      long currentTimeMills(); 1970年からのミリ秒単位の時刻が取得できます

    7. AWT
       AWTはグラフィック機能を提供します。