staticとnew

static

static という形容詞がいつも main() に付いていますね。たとえば

class Hello {
    public static void main(String[] args) {
        System.out.println("こんにちは");
    }
}

という具合です。

この static について,ちょっと実験してみましょう。次のようなプログラムを作ります。

class Test {
    static int value;
    static void setValue(int x) {
        value = x;
    }
    public static void main(String[] args) {
        setValue(5);
        System.out.println("値は " + value + " です");
    }
}

これを実行すると「値は 5 です」と画面に現れます。

この static という語を外してみましょう(main() の頭の static は残しておきます)。

class Test {
    int value;
    void setValue(int x) {
        value = x;
    }
    public static void main(String[] args) {
        setValue(5);
        System.out.println("値は " + value + " です");
    }
}

これで javac Test.java としてみると,次のようなエラーメッセージが出て,コンパイルできません。

Test.java:7: static でない メソッド setValue(int) を static コンテキストから参照することはできません。
        setValue(5);
        ^
Test.java:8: static でない 変数 value を static コンテキストから参照することはできません。
        System.out.println("値は " + value + " です");
                                   ^
エラー 2 個

これは要するに

static なメソッドから static でないものを使えないよ

という意味のエラーメッセージです。

new

static なものは,コンパイルした時点で作成されます。ところが,static でないものは,コンパイルした時点ではまだ存在しません。実行時に,new という命令を使って,自分で作らなければならないのです。

上のプログラムを正しくすると,次のようになります。

class Test {
    int value;
    void setValue(int x) {
        value = x;
    }
    public static void main(String[] args) {
        Test t = new Test();  // Test のインスタンス t を作る
        t.setValue(5);
        System.out.println("値は " + t.value + " です");
    }
}

new でできたものを,そのクラスのインスタンスといいます。インスタンスの作り方の決まり文句は,

    クラスの名前 インスタンスの名前 = new クラスの名前();

です。上の例では

        Test t = new Test();

となっていますね。Test がクラスの名前,t がインスタンスの名前です。

一つのクラスから複数のインスタンスを作ってもかまいません。たとえば

class Test {
    int value;
    void setValue(int x) {
        value = x;
    }
    public static void main(String[] args) {
        Test t = new Test();  // Test のインスタンス t を作る
        Test u = new Test();  // Test のインスタンス u を作る
        t.setValue(5);  // t の value を 5 にする
        u.setValue(7);  // u の value を 7 にする
        System.out.println("値は " + t.value + " です");
        System.out.println("値は " + u.value + " です");
    }
}

とすれば,

値は 5 です
値は 7 です

と出力されます。

このように,クラスの static でない部分は,一種の型紙のようなもので,それだけでは使えませんが,それからいくつでもインスタンスを作り出すことができます。

このように考えれば,mainstatic でなければならないのも当然ですね。main が最初から存在しなければ何もできないからです。

配列

配列とは,変数の並びです。たとえば100個の変数が必要なとき,

    int a, b, c, d, e, ...;

のようにいちいち作っていては日が暮れてしまいます。これを

    int[] a = new int[100];

のようにすれば,

a[0]a[1]a[2],……,a[99]

という100個の変数ができます。

この

    int[] a = new int[100];

    int[] a;
    a = new int[100];

のように分けて書いてもかまいません。

a という配列の長さは,a.length として得られます。上の例では a.length は100です。

次の例を見てください。

class Test {
    public static void main(String[] args) {
        long[] value = new long[92];
        value[0] = value[1] = 1;
        for (int i = 2; i < value.length; i++) {
            value[i] = value[i-1] + value[i-2];
            System.out.println("value[" + i + "] = " + value[i]);
        }
    }
}

3行目で value[0] から value[91] までの92個の long 型の変数を作っています。

Javaでは,クラスのインスタンスと同様に,配列も new という命令で作りますが,これはクラスのインスタンスとは違うものです。

上のプログラムを次のようにするとエラーになります。

class Test {
    long[] value;  // ここに持っていくとエラーになる
    public static void main(String[] args) {
        value = new long[92];
        value[0] = value[1] = 1;
        for (int i = 2; i < value.length; i++) {
            value[i] = value[i-1] + value[i-2];
            System.out.println("value[" + i + "] = " + value[i]);
        }
    }
}

static なメソッドから static でないものは使えないからです。対処法は,上の2行目を

    static long[] value;

とするか,あるいはインスタンスを作って

class Test {
    long[] value;
    public static void main(String[] args) {
        Test t = new Test();
        t.value = new long[92];
        t.value[0] = t.value[1] = 1;
        for (int i = 2; i < t.value.length; i++) {
            t.value[i] = t.value[i-1] + t.value[i-2];
            System.out.println("value[" + i + "] = " + t.value[i]);
        }
    }
}

とすればいいのでしたね。配列を作るのにも new を使うので混乱しやすいと思いますが,クラスのインスタンスを作るのを忘れないでください。

なお,次のような書き方もできます。

class Test {
    static long[] value = new long[92];
    public static void main(String[] args) {
        value[0] = value[1] = 1;
        for (int i = 2; i < value.length; i++) {
            value[i] = value[i-1] + value[i-2];
            System.out.println("value[" + i + "] = " + value[i]);
        }
    }
}

次の書き方も大丈夫です。

class Test {
    long[] value = new long[92];
    public static void main(String[] args) {
        Test t = new Test();
        t.value[0] = t.value[1] = 1;
        for (int i = 2; i < t.value.length; i++) {
            t.value[i] = t.value[i-1] + t.value[i-2];
            System.out.println("value[" + i + "] = " + t.value[i]);
        }
    }
}

static にしない場合,インスタンス名.変数名 のような書き方が面倒なら,次のように static でないメソッドに実際の作業をさせてしまうと楽です。

class Test {
    long[] value = new long[92];
    void doit() {
        value[0] = value[1] = 1;
        for (int i = 2; i < value.length; i++) {
            value[i] = value[i-1] + value[i-2];
            System.out.println("value[" + i + "] = " + value[i]);
        }
    }
    public static void main(String[] args) {
        Test t = new Test();
        t.doit();
    }
}

つまり,static でないメソッドからなら,インスタンス名を付けないで変数やメソッドが使えます。これは,同じインスタンスの中だけの話です。

なお,この main() の中はさらに

        new Test().doit();

のように2行を1行に縮めて書くことができます。


奥村晴彦

Last modified: 2005-12-25 12:29:04