クラスとオブジェクト

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

    1. クラスとは

      クラスは何らかの「モノ」を表現するもので、言語Cの構造体を拡張したものと考えることもできます。クラスでは変数だけでなくメソッド(関数)も内部に定義できます。
      クラスは次のように定義します。クラス内部で宣言された要素(変数およびメソッド)をメンバーと呼びます。
       class クラス名{ クラスのメンバ,..... }
      で定義します。クラスは1種の型宣言で、実行時に必要なメモリ領域は指定されません。。
       クラス名 名前 = new クラス名();
      で、クラスに対応する「実体」を宣言できます。この「実体」をクラスのインスタンスと呼びます(オブジェクトと呼ぶこともあります)。new によりクラスの型に対応した領域が割り当てられます。これがインスタンスの「実体」です。
       名前.メンバ
      で、クラスのメンバーを指定できます。

    2. 変数のみのクラス

       最初に変数のみから構成されるクラスを紹介します。文字列 name と整数 age から構成されるクラス man を定義します。クラス mantest クラスの main() で、クラスMan のインスタンス m1 と m2 を作成し、name と age に値を設定し、表示します。このクラスは、C言語の構造体と同等です。
      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. メソッドを含むクラス

       クラスにはメソッドも定義できます。クラスのインスタンスに対し
        インスタンス.メソッド()
      で、そのインスタンスのメソッドを実行(呼び出す)することができます。


      コンストラクタ、および、setAge、isYoung()、メソッドを定義したクラス Man2 を定義します。new Man2() で、コンストラクタを呼び出し、名前を指定します。また、getName()は名前を返すメソッド、isYung は age が18以下のとき true を返すメソッドです。
      class Man2{
        private String name;
        private int age;
      
       public void setName(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();//コンストラクタを呼び出す
         m2.setName("abe");
         m2.setAge(20);
         System.out.println(m2.getName()+":"+m2.isYoung());
        }
      }

    4. コンストラクタ

      クラス名と同じ名前で型指定のないメソッドを定義することができます。このメソッドはコンストラクタと呼ばれ、new でクラスを元にインスタンスを生成するときに、自動的に呼び出されます。コンストラクタにも引数を設定できます。
       引数の違いで複数のコンストラクタを用意できます。new に引数を指定すると対応するコンストラクタが実行されます。
      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 引数付きコンストラクタ
      コンストラクタで名前と年齢を同時に設定します。
      class Man2{
        private String name;
        private int age;
      
        Man2(String nm,int ag){//コンストラクタ
          name=nm;
          age=ag;
        }
      
        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",20);//コンストラクタを呼び出す
         System.out.println(m2.getName()+":"+m2.isYoung());
        }
      }
  2. クラスとstatic修飾子

    1. static宣言された変数

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

      例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()は new で生成できませんから、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キーワード

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

    4. クラスの配列を利用

       クラスの配列を利用するには、配列の要素に予めインスタンスを作成しておく必要があります。次の例では、「座標」を記憶する 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++; 

    5. アクセス指定子と有効範囲

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

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


    1. ガベージコレクション

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

    2. 循環参照

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

    3. 実行速度

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