Javaのstaticって何? — フィールド・メソッド・ブロックの使い分け
はじめに
Javaを書いていると static という単語をよく見かけます。
public static void main(String[] args) { ... }
private static int count = 0;
static { ... }
「おまじないでつけてる」「なんとなく動いてる」という方も多いと思います。
この記事では static の本質的な意味と、フィールド・メソッド・ブロックそれぞれでの使い方を整理します。
static の本質 —「インスタンスではなくクラスに属する」
Javaでは通常、フィールドやメソッドはインスタンス(オブジェクト)に属します。
Car car1 = new Car();
Car car2 = new Car();
// car1 と car2 はそれぞれ独立したフィールドを持つ
static をつけると、クラスそのものに属するようになります。インスタンスを作らなくても使えて、全インスタンスで共有されます。
クラス(設計図)
├── static フィールド ← 全インスタンスで1つだけ
├── static メソッド ← インスタンスなしで呼べる
│
├── インスタンス1
│ └── 通常フィールド
└── インスタンス2
└── 通常フィールド
static フィールド — 全インスタンスで共有する値
public class Car {
private static int count = 0; // 全インスタンスで共有
private String name;
public Car(String name) {
this.name = name;
count++; // 生成のたびに1増える
}
public static int getCount() {
return count;
}
}
Car car1 = new Car("プリウス");
Car car2 = new Car("アクア");
Car car3 = new Car("ヤリス");
System.out.println(Car.getCount()); // 3
ポイント: count は全インスタンスで1つだけ存在します。どのインスタンスが変更しても、全体に反映されます。
よくある使い方
// 定数(static + final の組み合わせ)
public class MathConstants {
public static final double PI = 3.14159265358979;
public static final double E = 2.71828182845904;
}
// 使う側
double area = MathConstants.PI * radius * radius;
static final の組み合わせは「クラス定数」として広く使われます。
static メソッド — インスタンスなしで呼べるメソッド
public class StringUtils {
public static String reverse(String s) {
return new StringBuilder(s).reverse().toString();
}
public static boolean isEmpty(String s) {
return s == null || s.isEmpty();
}
}
// インスタンスを作らずに呼べる
String reversed = StringUtils.reverse("hello"); // "olleh"
boolean empty = StringUtils.isEmpty(""); // true
ポイント: static メソッドの中では this が使えません。インスタンスのフィールドにもアクセスできません。
public class Counter {
private int count = 0;
public static void badMethod() {
System.out.println(count); // コンパイルエラー!
// static メソッドからインスタンスフィールドにはアクセス不可
}
}
Javaの標準ライブラリでの例
// Math クラスはすべて static メソッド
Math.abs(-5); // 5
Math.max(3, 7); // 7
Math.sqrt(16.0); // 4.0
// Arrays クラスも同様
Arrays.sort(arr);
Arrays.toString(arr);
// Collections も同様
Collections.sort(list);
Collections.reverse(list);
これらはインスタンスを作らずに使えます。「ユーティリティクラス」と呼ばれるパターンです。
static ブロック — クラスが読み込まれた時に一度だけ実行
public class Config {
private static final Map<String, String> settings;
static {
// クラスが最初に使われた時に一度だけ実行される
settings = new HashMap<>();
settings.put("host", "localhost");
settings.put("port", "8080");
settings.put("db", "mydb");
}
public static String get(String key) {
return settings.get(key);
}
}
String host = Config.get("host"); // "localhost"
ポイント: static ブロックはクラスがJVMに読み込まれた時に1回だけ実行されます。複雑な初期化処理をまとめるのに使います。
まとめ
| 種類 | 意味 | よくある使い方 |
|---|---|---|
| static フィールド | 全インスタンスで共有する値 | カウンター、定数(static final) |
| static メソッド | インスタンスなしで呼べるメソッド | ユーティリティ処理、ファクトリメソッド |
| static ブロック | クラス読み込み時に1回だけ実行 | 複雑な初期化処理 |
おわりに
static の本質は「クラスに属する」です。
- インスタンスを作らなくても使いたい → static メソッド
- 全インスタンスで共有したい / 定数にしたい → static フィールド
- クラス読み込み時に初期化したい → static ブロック
public static void main の static も「インスタンスなしでJVMが呼び出せるように」という意味です。これで main メソッドの static も腑に落ちたのではないでしょうか。