Javaに関する様々な情報をご紹介します。

Javaに関する様々な情報をご紹介します。

static

このページでは、static修飾子が付与されたクラスメンバ変数、クラスメソッドについて説明します。

概要

メンバ変数、メソッドを宣言する際、static修飾子が付与されたものをクラスメンバ変数、クラスメソッド、static修飾子が付与されていないものをインスタンスメンバ変数、インスタンスメソッドと言い、両者で性質が異なります。

クラスメンバ変数、クラスメソッドはそのクラス内で1つという位置付けです。そのクラスからいくつオブジェクトを生成してもオブジェクトごとにメンバ変数、メソッドが割り当てられることはありません。

クラスメンバ変数、クラスメソッドの位置付け

クラスメンバ変数、クラスメソッドの位置付け

インスタンスメンバ変数、インスタンスメソッドはオブジェクトごとに存在します。クラスからオブジェクトが生成されるとそれぞれのオブジェクトに対し、インスタンスメンバ変数、インスタンスメソッドが割り当てられます。

インスタンスメンバ変数、インスタンスメソッドの位置付け

インスタンスメンバ変数、インスタンスメソッドの位置付け

クラスメンバ変数、クラスメソッドはオブジェクトに依存しないため、オブジェクト指向という観点から言えばそれほど使用されるということはありません。クラスメンバ変数、クラスメソッドは以下のケースにおいてよく使用されます。

  1. オブジェクト間で共通の値を保持したい時にクラスメンバ変数を使用します。
  2. 定数を宣言する際に、final修飾子と供に使用されます。ロケール定数など標準APIで用意されている定数はほとんどstatic finalで宣言されています。
  3. 公式的な処理を行うメソッドにクラスメソッドを使用します。クラスMathで用意されているsin、cosなどはstatic修飾子が付与され宣言されています。
  4. オブジェクトが生成されていなくても処理を行う必要があるときにクラスメソッドを使用します。クラスメソッドはオブジェクトに依存しないため、オブジェクトが生成されていなくても実行できます。mainメソッドはオブジェクトを生成する前に実行する必要があるため、static修飾子を付けて宣言しています。

【例1】クラスメンバ変数とインスタンスメンバ変数の違いを例示します。

class ExClass12{
    //(1)クラスメンバ変数の宣言
    static int classV;
    //(2)インスタンスメンバ変数の宣言
    int instanceV;

    public static void main(String[] args) {
        ExClass12 object1 = new ExClass12();
        ExClass12 object2 = new ExClass12();

        object1.classV = 100;  //(3)
        object2.classV = 200;  //(4)
        object1.instanceV = 100;  //(5)
        object2.instanceV = 200;  //(6)

        System.out.println(object1.classV +
            ":" + object2.classV);  //(7)
        System.out.println(object1.instanceV +
            ":" + object2.instanceV);  //(8)
    }
}

解説1

  1. (1)static修飾子を付与し、クラスメンバ変数classVを宣言します。
  2. (2)インスタンスメンバ変数instanceVを宣言します。
  3. (3)オブジェクト変数object1を通し、クラスメンバ変数classVに値100を代入します。
  4. (4)オブジェクト変数object2を通し、クラスメンバ変数classVに値200を代入します。
  5. (5)オブジェクト変数object1を通し、インスタンスメンバ変数instanceVに値100を代入します。
  6. (6)オブジェクト変数object2を通し、インスタンスメンバ変数instanceVに値200を代入します。
  7. (7)object1.classVとobject2.classVの値を表示します。classVはクラスメンバ変数のため、クラス内に1つのみ存在し、オブジェクト間で共有されます。そのため「200:200」が表示されます。
  8. (8)object1.instanceVとobject2.instanceVの値を表示します。instanceVはインスタンスメンバ変数のため、オブジェクトごとに値が保持されます。そのため「100:200」が表示されます。

実行結果1

D:\JAVA>javac ExClass12.java

D:\JAVA>java ExClass12
200:200
100:200

D:\JAVA>

参照方法

クラス要素とインスタンス要素は参照方法も異なります。以下の表はそれぞれの参照方法を表します。

参照方法 クラスメンバ変数
クラスメソッド
インスタンスメンバ変数
インスタンスメソッド
単純名による参照 △(※)
オブジェクト変数名
による参照
クラス名による参照 ×

クラスメンバ変数、クラスメソッド

  1. 単純名による参照

    クラスメンバ変数、クラスメソッドは参照元メソッドから単純名により参照することができます。

    例2

    class ExClassA{
        //クラスメンバ変数の宣言・生成
        static String classV = "クラスメンバ変数classV";
        //クラスメソッドの宣言
        static void classM() {
            System.out.println("クラスメソッドclassM");
        }
    
        public static void main(String[] args) {
            //単純名でのクラスメンバ変数の参照
            System.out.println(classV);
            //単純名でのクラスメソッドの参照
            classM();
        }
    }
  2. オブジェクト変数名による参照

    クラスメンバ変数、クラスメソッドは参照元メソッドからオブジェクト変数を通して参照することも許容されています。 但し、クラスメンバ変数、クラスメソッドがオブジェクトに依存しないと言う性質を考えるとあまり推奨された参照方法ではありません。

    例3

    class ExClassA{
        //クラスメンバ変数の宣言・生成
        static String classV = "クラスメンバ変数classV";
        //クラスメソッドの宣言
        static void classM() {
            System.out.println("クラスメソッドclassM");
        }
    
        public static void main(String[] args) {
            //ExClassAクラスのオブジェクトobject1の宣言・生成
            ExClassA object1 = new ExClassA();
            //オブジェクト変数を通してのクラスメンバ変数の参照
            System.out.println(object1.classV);
            //オブジェクト変数を通してのクラスメソッドの参照
            object1.classM();
        }
    }
  3. クラス名による参照

    クラスメンバ変数、クラスメソッドを参照元メソッドからクラス名を通して参照します。クラスメンバ変数、クラスメソッドがクラス内で1つのみ存在するという性質を考えると最も推奨される参照方法です。

    例4

    class ExClassA{
        //クラスメンバ変数の宣言・生成>
        static String classV = "クラスメンバ変数classV";
        //クラスメソッドの宣言>
        static void classM() {
            System.out.println("クラスメソッドclassM");
        }
    
        public static void main(String[] args) {
            //クラス名を通してのクラスメンバ変数の参照>
            System.out.println(ExClassA.classV);
            //クラス名を通してのクラスメソッドの参照
            ExClassA.classM();
        }
    }

インスタンスメンバ変数、インスタンスメソッド

  1. 単純名による参照

    インスタンスメンバ変数、インスタンスメソッドも単純名により参照することができます。但し、参照元メソッドがクラスメソッドの場合は単純名により参照することはできません。コンパイルエラーとなります。理由は、インスタンスメソッドは属するオブジェクトを表すthisというものをメソッド内に持っているのですが、クラスメソッドは個々のオブジェクトに属さないためメソッド内にthis を持っていないためです。mainメソッド(クラスメソッド)から単純名でインスタンスメンバ変数、インスタンスメソッドを参照できないのはこの理由のためです。

    インスタンスメソッド内で単純名によりインスタンスメンバ変数、インスタンスメソッドを参照する場合、コンパイル時に暗黙にthis.単純名に変換されて参照されています。このため、どのオブジェクトに属するインスタンスメンバ変数、インスタンスメソッドを参照すればいいのかがわかります。

    例5

    class ExClassA{
        //インスタンスメンバ変数の宣言・生成
        String instanceV = "インスタンスメンバ変数instanceV";
        //インスタンスメソッドの宣言
        void instanceM() {
            System.out.println("インスタンスメソッドinstanceM");
        }
    
        void show() {
            //単純名でのクラスメンバ変数の参照
            System.out.println(instanceV);
            //単純名でのクラスメソッドの参照
            instanceM();
        }
    
        public static void main(String[] args) {
            //クラスメソッドからインスタンスメソッドshowを
            //単純名で参照できません。
            //show();  ←コンパイルエラー
            ExClassA object1 = new ExClassA();
            //インスタンスメソッドshowの参照
            object1.show();
        }
    }
  2. オブジェクト変数名による参照

    インスタンスメンバ変数、インスタンスメソッドは参照元メソッドからオブジェクト変数を通して参照することができます。

    例6

    class ExClassA{
        //インスタンスメンバ変数の宣言・生成
        String instanceV = "インスタンスメンバ変数instanceV";
        //インスタンスメソッドの宣言
        void instanceM() {
            System.out.println("インスタンスメソッドinstanceM");
        }
        public static void main(String[] args) {
            //ExClassAクラスのオブジェクトobject1の宣言・生成
            ExClassA object1 = new ExClassA();
            //オブジェクト変数を通してのインスタンスメンバ変数の参照
            System.out.println(object1.instanceV);
            //オブジェクト変数を通してのインスタンスメソッドの参照
            object1.instanceM();
        }
    }

10static