Java 逆引き集 | static とインスタンスの違い - 状態管理

Java Java
スポンサーリンク
スポンサーリンク

static とインスタンスの違いを「誰の持ち物か」で捉える

Java の static とインスタンスの違いは、一言で言えば「それはクラス全体の持ち物か、それとも“その1個”だけの持ち物か」という違いだ。 static は「クラスの持ち物」、インスタンスフィールドやインスタンスメソッドは「生成されたオブジェクト1つ1つの持ち物」になる。

例えば、次のようなクラスを考える。

public class Counter {
    private static int totalCount = 0;   // クラス全体で共有される
    private int myCount = 0;             // インスタンスごとに別々

    public Counter() {
        totalCount++;
    }

    public void increment() {
        myCount++;
    }

    public int getMyCount() {
        return myCount;
    }

    public static int getTotalCount() {
        return totalCount;
    }
}
Java

ここで totalCountstatic フィールドなので、「Counter クラスとして何個作られたか」を全インスタンスで共有する。 一方 myCount はインスタンスフィールドなので、「この Counter が何回 increment されたか」を、そのインスタンスだけが持つ。

この違いを「誰の持ち物か」という視点で捉えると、状態管理の設計がぐっと分かりやすくなる。

インスタンスの状態管理(「その1個だけの物語」を持たせる)

インスタンスフィールドは、「そのオブジェクト1つだけが持つ状態」を表現するためのものだ。 例えば、ユーザーを表すクラスなら、名前や年齢はインスタンスごとに違う。

public class User {
    private final String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void birthday() {
        age++;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}
Java

User を2人作れば、それぞれ別の状態を持つ。

User u1 = new User("Taro", 20);
User u2 = new User("Hanako", 25);

u1.birthday(); // Taro は 21 歳になる
System.out.println(u1.getAge()); // 21
System.out.println(u2.getAge()); // 25
Java

ここで重要なのは、「インスタンスの状態は、そのインスタンスだけの物語を表している」ということだ。 u1 の誕生日を祝っても u2 には影響しない。 この「独立した状態」を持たせるのがインスタンスフィールドであり、「その1個だけの物語」を書く場所がインスタンスメソッドだと言える。

static の状態管理(「クラス全体の統計やルール」を持たせる)

一方 static は、「クラス全体として共有したい状態」や「インスタンスに紐づかないルール」を表現するために使う。 先ほどの Counter の例では、「Counter が何個作られたか」という統計を static で持っていた。

Counter c1 = new Counter();
Counter c2 = new Counter();
Counter c3 = new Counter();

System.out.println(Counter.getTotalCount()); // 3
System.out.println(c1.getMyCount());         // 0
System.out.println(c2.getMyCount());         // 0
Java

totalCount は「Counter クラスとしての総数」であり、どのインスタンスから見ても同じ値になる。 このような「全体の統計」「全体の設定」「共通の定数」は、static フィールドとして持つのが自然だ。

例えば、定数を表すときも static がよく使われる。

public class AppConfig {
    public static final String APP_NAME = "MyApp";
    public static final int MAX_USERS = 1000;
}
Java

呼び出し側はインスタンスを作らずに、クラス名から直接参照する。

System.out.println(AppConfig.APP_NAME);
System.out.println(AppConfig.MAX_USERS);
Java

ここでは「アプリ全体の設定」であり、「個々のユーザーごとに違うもの」ではない。 だからこそ static としてクラスの持ち物にするのがふさわしい。

static メソッドとインスタンスメソッドの違い(「何に対して処理するか」)

メソッドについても、「何に対して処理するか」という視点で static とインスタンスの違いを捉えると分かりやすい。

インスタンスメソッドは、「このオブジェクトに対して処理する」ためのものだ。

public class User {
    private final String name;

    public User(String name) {
        this.name = name;
    }

    public String greet() {
        return "Hello, " + name;
    }
}
Java

呼び出し側はインスタンスを作ってから、そのインスタンスに対してメソッドを呼ぶ。

User u = new User("Taro");
System.out.println(u.greet()); // Hello, Taro
Java

ここでは「Taro というユーザーに対して挨拶文を作る」という意味になる。

一方 static メソッドは、「特定のインスタンスに紐づかない処理」を表現するために使う。

public class StringUtil {

    public static String toUpper(String s) {
        return s.toUpperCase();
    }
}
Java

呼び出し側はインスタンスを作らずに、クラス名から直接呼び出す。

String result = StringUtil.toUpper("hello");
System.out.println(result); // HELLO
Java

ここでは「文字列を大文字にする」という処理であり、「StringUtil のインスタンス」に紐づく必要はない。 つまり、「この処理は特定のオブジェクトの状態を変えたり読んだりしないか?」という問いに「はい」と答えられるならインスタンスメソッド、「いいえ」と答えられるなら static メソッドにする、という判断軸が使える。

状態管理の設計で意識すべきポイント(static を増やしすぎない)

状態管理の設計で特に重要なのは、「static を安易に増やしすぎない」ことだ。 static フィールドはクラス全体で共有されるため、一度値が変わると全インスタンスに影響する。 これは「グローバル変数」に近い性質を持っていて、乱用するとバグの原因になる。

例えば、次のようなコードを考える。

public class Session {
    public static String currentUserName;
}
Java

どこかでログイン処理がこう書かれている。

Session.currentUserName = "Taro";
Java

別の場所でこう書かれている。

Session.currentUserName = "Hanako";
Java

このとき、「どのタイミングで誰が currentUserName を書き換えたか」を追うのが非常に難しくなる。 複数スレッドが同時にアクセスするような環境では、さらに問題が深刻になる。

「その状態は本当に全体で共有すべきか?」「特定のインスタンスに紐づけられないか?」という問いを常に持ち、 共有すべきでないものはインスタンスフィールドとして持たせる方が、安全で予測しやすいコードになる。

逆に、「全体で共有すること自体が仕様である」もの——例えば「アプリケーションの起動回数」「全ユーザー数の統計」「共通設定」など——は、static で持つことに意味がある。 状態管理の設計は、「何が個別の物語で、何が全体のルールや統計なのか」を見極める作業だと言っていい。

まとめとテンプレート的な考え方

static とインスタンスの違いは、「それがクラス全体の持ち物か、生成されたオブジェクト1つ1つの持ち物か」という違いであり、状態管理の設計と直結している。 インスタンスフィールドとインスタンスメソッドは「その1個だけの物語」を表現し、static フィールドと static メソッドは「全体のルールや統計」を表現する。

テンプレート的に考えるなら、次のような問いを自分に投げかけるとよい。

この値は、オブジェクトごとに違うべきか? この処理は、特定のオブジェクトの状態を前提にしているか? この情報は、アプリケーション全体で共有されるべきか?

「違うべき」「前提にしている」と感じるならインスタンス側に寄せ、「共有されるべき」と感じるなら static 側に寄せる。 その判断を積み重ねていくことで、状態管理が整理されたコードベースに近づいていく。

タイトルとURLをコピーしました