クラスとオブジェクト

  1. クラス
    1. 単純なクラス
    2. フィールド
    3. アクセス制御と継承
  2. オブジェクト
    1. オブジェクトの生成
    2. コンストラクタ
    3. メソッド
    4. this
    5. super
    6. メソッドのオーバロード
    7. static メンバ
    8. main
    9. ネイティブメソッド
  3. ガーベジコレクション

  1. クラス
  2. java プログラムの基本単位はクラスです。
    クラスにはフィールドメソッドがあります。

    java のオブジェクトには、 タイプがあります。 すなわちクラスがオブジェクトのタイプです。

    クラスは、オブジェクトの構造を定義します。 クラス定義は、オブジェクトを生成するためのメカニズムを提供します。

    すなわち、クラスを設計図と生産手順マニュアルをもつ工場、 オブジェクトを工場から生産される製品と考えるとわかりやすいでしょう。

    1. 単純なクラス
    2. クラスの基本は、 フィールド(データ)とメソッド(データを操作するためのコード)です。
      クラス Body を見てみましょう。

      class Body{
         public long idNum;
         public String nameFor;
         public Body orbits;
       
         public static long nextID = 0;
      
      // constructor_1
         Body() {
           idNum = nextID++;
         }
      // constructor_2
         Body(String bodyName,Body orbitsAround) {
           this();
           nameFor = bodyName;
           orbits  = orbitsAround;
         }
         void Earth() {
           Body sun   = new Body("Sun",null);
           Body earth = new Body("Earth",sun);
         }
      }
      

      クラス Body を宣言します。オブジェクトへの参照は以下の通りです。

         Body mercury;
      

    3. フィールド
    4. クラスの変数はフィールドと呼ばれます。
      クラス Body 内の idNum,nameFor,orbits,nextID はフィールドの例です。

      ときにはフィールドのインスタンスを、 同じクラスの他のすべてのオブジェクトと共有したいときがあります。 このようなフィールドは static と宣言することで得られます。 クラス内で staticフィールドを宣言すると、 そのクラスから生成されたすべてのオブジェクトは、そのフィールドを共有します。

    5. アクセス制御と継承
    6. クラス内のコードからは、 常に同じクラスのすべてのフィールドとメソッドにアクセスできます。
      他のクラスのコードからオブジェクトへのアクセスを制限したり、 サブクラスによる継承を制御するため、 以下の4つのアクセス修飾子 のいずれかを指定でき、 その指定順に制限はありません。

      以下の表は、アクセス制限の厳しい順に並べたものです。

      アクセス修飾子 意               味
      private 自分のクラス以外からは見えない。
      無指定
      [デフォルト]
      アクセス修飾子なしで宣言されたメンバは、 同じパッケージ内のコードからアクセスできます。 また同じパッケージのサブクラスによってのみ継承されます。
      protected パッケージ内のほかのクラスおよびパッケージ内外のサブクラスからアクセスできます。
      public そのクラスを参照できるすべてのコードからアクセスできます。
      またこのメンバはサブクラスに継承されます。

      質問 この Body の設計はよくない。どこが悪いのでしょうか?

  3. オブジェクト
    1. オブジェクトの生成
    2. new はオブジェクトを生成する一般的な方法です。
      オブジェクトを new で生成するときは、オブジェクトのタイプと引数を指定します。 java ランタイムシステムは、 オブジェクトのフィールドに必要な領域を確保し、初期化します。 初期化が完了すると、生成したオブジェクトの参照を返します。
      このとき呼ばれるのが、クラスのコンストラクタです。

      クラス定義からオブジェクトを生成することを、 インスタンス化と言います。 このためオブジェクトは、 インスタンスと呼ばれることもあります。

      java のオブジェクトはヒープに置かれ、 オブジェクトへの参照を介してのみアクセスできます。 参照すべきオブジェクトがない参照は null です。 参照とは、cでいうポインタのことです。

    3. コンストラクタ (構築子) (constructor)
    4. 新しく生成されたオブジェクトは初期状態になります。
      通常、フィールドは宣言した値で初期化されます。
      単純な初期化では済まないときのために、クラスはコンストラクタをもてます。

      コンストラクタは、初期化するクラスと同じ名前でなければなりません。

      コンストラクタは引数をもてますが、メソッドではないので、 戻り値はもてません
      それは new で呼び出されます。

      例えば Body では、具体的な天体を表すオブジェクトは以下のように生成され、 初期化されます。

      Body sun    = new Body();
      sun.idNum   = Body.nextID++;
      sun.nameFor = "Sun";
      sun.orbits  = null;
      
      Body earth    = new Body();
      earth.idNum   = Body.nextID++;
      earth.nameFor = "Earth";
      earth.orbits  = sun;
      

    5. メソッド
    6. クラスのメソッドには、オブジェクトの状態を知り、操作するコードが含まれます。 メソッドは、オブジェクトへの操作として参照と演算子 . によってよびだされます。

      メソッドは、適当な数の引数をもてますが、 可変個の引数をもつものは定義できません。

        参照名.メソッド名(引数列);
      
      

      戻り値

      値を戻さないメソッドの戻り値のタイプは void です。 値を戻すメソッドの戻り値のタイプはオブジェクトの型です。

      値を戻すには、以下のようにします。

         return 戻り値;      ただし、戻り値のタイプは宣言と同じでなければなりません。
      
      

      引数

      メソッドの引数はすべて値渡しです。 つまり呼び出すとき指定した変数値のコピーです。 従って呼び出されたメソッド内で値を変えても、 呼び出し側の値は影響されません。

      引数は、() で囲まれた中に書きます。

    7. this
    8. static でないメソッド内で使うことができる特殊な参照 this は、呼び出されているメソッドの現在のオブジェクトを示します。 参照 this は、 他のメソッドにオブジェクト自身を引数として渡すために使われることが多いです。

      フィールドやメソッドの前に参照がないときは、暗黙で this がつきます。

    9. super
    10. super は、拡張クラスのすべての static でないメソッドから利用できます。

      フィールドをアクセスしたりメソッドを呼び出すとき、 super は現在の(super を呼び出した)オブジェクトを、 スーパクラスのインスタンスとみなし、 そのオブジェクトに対する参照として動作します。

      super は、参照のタイプにより どのメソッドの実装を使用するかを選択するときに限られます。

      class That {
         protected String nm() {
            return "That";
         }
      }
      class More extends That {
         protected String nm() {
            return "More";
         }
         public static void main(String[] args) {
            More m = new More();
            m.printNM();
         }
         protected void printNM() {
            That sref = new More();
      
            System.out.println("this.nm()  = "+this.nm());
            System.out.println("sref.nm()  = "+sref.nm());
            System.out.println("super.nm() = "+super.nm());
         }
      }
      
      osaka-43] java More
      this.nm()  = More
      sref.nm()  = More
      super.nm() = That
      

      名前が衝突すると何がおこるか?

      スーパクラスの変数とサブクラスの変数が同じ名前だった場合は、 サブクラスの変数がスーパクラスの変数に取ってかわります (スーパクラスの変数を隠す)。 見える方の変数、すなわちサブクラスの変数が、 スーパクラスの変数を覆ってしまいます。

      スーパクラスの変数もフルネームを使えばアクセス可能です。
      スーパクラス名.変数名でもよいし、 キーワード super を使って super.変数名としてもよいです。

      スーパクラスの変数名とサブクラスのメソッド名が同じだった場合やその逆の場合は、
      コンパイル・エラーになります。

    11. メソッドのオーバロード
    12. java のメソッドにはシグネチャがあります。 シグネチャはメソッド名と引数の数とタイプの総称です。

      シグネチャが異なる2つのメソッドは、同じ名前をもてます。
      これをオーバロードと言います。

         public Body orbitsAround() {
            return orbits;
         }
         public void orbitsAround(Body around) {
            orbits = around;
         }
      

    13. static メンバ
    14. クラスのメンバは、フィールドとメソッドの2つです。 static メンバは、各オブジェクトに対して1つづつ存在するのではなく、 クラスに対して1つしか存在できません。

      static 初期化ブロック

      クラスは、static フィールドまたは他の必要な状態を定めるために static 初期化ブロックをもてます。

      static 初期化子は、 フィールド宣言での単純な初期化だけでは充分でない場合に有用です。 例えば static な配列を生成し、そのメンバを初期化する場合などです。

      class Primes {
         protected static int [] knownPrimes = new int[4];
      
         static {
            knownPrimes[0] = 2;
            for (int i= 1; i< knownPrimes.length; i++)
                knownPrimes[i] = nextPrime();
         }
      
         private static int nextPrime(){ ..... }
      }
      

      static メソッド

      static メソッドはクラスに対してよびだされます。普通のメソッドのように、 クラスからインスタンス化されたオブジェクトに対して呼び出されるのではありません。

      static メソッドはクラスの static 変数および static メソッドにのみアクセスできます。 特定のオブジェクトのメソッドではないので、参照 this を使えません。 たとえば、上記の static メンバへのアクセスは以下のようになります。

         prime    = Primes.nextPrime();
         knownCnt = Primes.knownPrimes.length;
      

    15. main
    16. java はクラスを実行するとき、 そのクラスの main メソッドを探し実行を開始します。

      main メソッドは、public かつ static かつ void でなければなりません。 また、引数は String[] 型です。これはプログラム引数で、 クラスを実行するとき入力したものが渡されます。

         public static void main(String[] args)
      
      

    17. ネイティブメソッド
    18. native 指定されたメソッドのことで、 java 言語以外の言語で書かれたプログラムを java から呼び出すためのインタフェースです。 java 言語以外で書かれたコードを使うような java プログラムを書くとき、 またはハードウェアを直接操作する必要があるときは、 ネイティブメソッドを書けます。 ただしネイティブメソッドを使うと、コードの移植性や安全性は失われるので、 最小限にとどめるべきです。

  4. ガーベジコレクション (Garbage Collection)
  5. 一般的には動的なデータ構造を持つ言語は、メモリが必要になった時に OS に要求し、不要になった時点で OS に戻します。

    java では、メモリを解放するのはプログラマではなく、 java の実行コンポネントであるガーベジコレクタです。

    ヒープとスタックという概念があります。
    スタックは、 手続き呼び出しと戻りに関係する動的なメモリ要求と、 局所変数のための領域として使います。 ヒープは、その他の動的メモリのために使われます。 スタックに確保される変数は、メソッドの局所変数だけです。 オブジェクトはヒープに確保されます。

    ガーベジコレクタは、残りのメモリが少なくなったり、 メモリが多量に必要になったとき起動され、 すでに使われなくなったヒープをメモリ領域に戻します。





まとめ

クラス フィールド + コンストラクタ + メソッド
オブジェクトの生成  変数名 = new クラス名();
main メソッド public static void main(String[] args){}

メソッドの呼び方

 static メソッド クラス名.メソッド名(引数列)  static でないメソッド オブジェクト名.メソッド名(引数列)