この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:4
ページ更新者:guest
更新日時:2026-06-11 07:07:02

タイトル: staticキーワード
SEOタイトル: Java static キーワード完全ガイド

この記事の要点
  • static はインスタンスに属さず、クラス自体に属するメンバ(変数 / メソッド / 内部クラス)を作るキーワード
  • static 変数 (クラス変数): 全インスタンスで 1 つの値を共有。Counter.count のようにクラス名でアクセス
  • static メソッド: new せず呼べる。Math.sqrt() / Integer.parseInt() が典型
  • static 初期化ブロック: クラスロード時に 1 回だけ実行。設定読み込みに使う
  • 欠点: グローバル状態 / テストが難しい / オーバーライドできない(隠蔽されるだけ)。シングルトンや純粋関数的なユーティリティに限定

static とは何か

static は Java(C# / C++ も同様)のキーワードで、クラス全体で共有されるメンバを宣言します。インスタンス(new したオブジェクト)ごとに別の値を持つ通常メンバとは対照的です。

種類所属アクセス方法
インスタンス変数各オブジェクトobj.field
static 変数クラス全体ClassName.field
インスタンスメソッド各オブジェクトobj.method()
static メソッドクラス全体ClassName.method()

static 変数 (クラス変数)

public class Counter {
    public static int total = 0;    // ★ static 変数(全インスタンス共有)
    private int id;                  // インスタンス変数(個別)

    public Counter() {
        total++;                     // 共有値をインクリメント
        this.id = total;
    }
}

Counter c1 = new Counter();    // total = 1, c1.id = 1
Counter c2 = new Counter();    // total = 2, c2.id = 2
Counter c3 = new Counter();    // total = 3, c3.id = 3

System.out.println(Counter.total);    // ★ クラス名でアクセス: 3
System.out.println(c1.id);            // 1

static メソッド

インスタンス化せずに呼べるメソッド。状態を持たない純粋関数に向きます。

public class MathUtils {
    public static int square(int n) {
        return n * n;
    }

    public static double average(int[] nums) {
        int sum = 0;
        for (int n : nums) sum += n;
        return (double) sum / nums.length;
    }
}

// new せずに呼べる
int sq = MathUtils.square(5);                      // 25
double avg = MathUtils.average(new int[]{1,2,3});  // 2.0

// 標準ライブラリの例
double pi = Math.PI;                  // static 定数
double s = Math.sqrt(16.0);           // static メソッド
int n = Integer.parseInt("42");       // static メソッド
String s2 = String.valueOf(123);      // static メソッド

static の制約

制約説明
this 不可static メソッドからは this を使えない(インスタンスが無い)
インスタンスメンバアクセス不可static から非 static フィールドを直接参照できない
オーバーライド不可static は隠蔽 (hiding) されるだけ。多態性なし
abstract と併用不可abstract static は無意味(abstract は実体オーバーライド前提)

static 初期化ブロック

クラスがロードされる時に1 度だけ実行されるブロック。複雑な初期化に。

public class Config {
    public static final Map SETTINGS;

    static {
        // クラスロード時に 1 回だけ実行される
        SETTINGS = new HashMap<>();
        SETTINGS.put("env",   System.getenv("APP_ENV"));
        SETTINGS.put("debug", System.getenv("APP_DEBUG"));
        // ファイルから設定読込なども可能
    }

    // インスタンス初期化ブロック(static 無し)は new ごとに実行
    {
        System.out.println("instance init");
    }
}

static インナークラス (Nested Class)

外部クラスのインスタンスに依存しない内部クラス。普通の内部クラス (inner class) と違い、外部の this を持たないのでメモリリークを防げます。

public class Outer {
    private int x;

    // ❌ 普通の内部クラス: Outer の this を暗黙保持 → リーク要注意
    class Inner {
        void show() { System.out.println(x); }  // 外部 x にアクセス可
    }

    // ✅ static インナークラス: Outer のインスタンス無しで作れる
    static class StaticInner {
        void show() { System.out.println("hi"); }
        // System.out.println(x); ← ★ コンパイルエラー: static から非 static 不可
    }
}

// 普通の内部: 外部インスタンスが必要
Outer.Inner inner = new Outer().new Inner();

// static: 外部不要
Outer.StaticInner si = new Outer.StaticInner();

static import

毎回 Math. と書きたくない場合に使う構文(Java 5+)。

// 通常
import java.lang.Math;
double a = Math.PI * Math.sqrt(16);

// static import
import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
double b = PI * sqrt(16);    // クラス名省略可

// ワイルドカード
import static java.lang.Math.*;
double c = PI * sqrt(16) + abs(-3);

// 注意: 乱用するとどのクラスのメソッドか分からなくなる
// JUnit5 の assertEquals / assertTrue 等で常用される
import static org.junit.jupiter.api.Assertions.*;

@Test
void testAdd() {
    assertEquals(4, 2 + 2);    // クラス名不要で読みやすい
}

シングルトンパターンと static

public class Logger {
    private static Logger instance;    // ★ static フィールドで唯一性を保証

    private Logger() { }    // 外部から new 禁止

    public static synchronized Logger getInstance() {
        if (instance == null) {
            instance = new Logger();
        }
        return instance;
    }

    public void log(String msg) {
        System.out.println("[LOG] " + msg);
    }
}

Logger.getInstance().log("hello");

ユーティリティクラス

状態を持たない static メソッドの集まり。private コンストラクタでインスタンス化を防ぐのが定石。

public final class StringUtils {
    private StringUtils() {    // ★ インスタンス化禁止
        throw new AssertionError("no instances");
    }

    public static boolean isBlank(String s) {
        return s == null || s.trim().isEmpty();
    }

    public static String reverse(String s) {
        return new StringBuilder(s).reverse().toString();
    }
}

StringUtils.isBlank("  ");    // true
// StringUtils s = new StringUtils();  ← コンパイル可だが実行時 AssertionError

static のメモリ管理

領域JVM バージョン説明
PermGenJava 7 以前クラス定義 / static フィールドが入る固定領域。サイズ不足で PermGen space エラー
MetaspaceJava 8+ネイティブメモリに移動。デフォルト無制限(最大値設定可: -XX:MaxMetaspaceSize

static フィールドはクラスがアンロードされるまで解放されません。巨大なオブジェクトを static に保持するとメモリリークの原因に。

static のアンチパターン

  • グローバル状態の濫用: テストごとに状態がリセットされず、テスト独立性が失われる
  • static でないとできない処理: ほとんどないので、可能なら DI で渡す
  • static 変数で動作変更: ある画面でセットした値が別画面に影響
  • Singleton の濫用: テストでモック注入が困難。代わりに DI コンテナを推奨

FAQ

Q: static メソッドはなぜテストしにくい?
A: モック化が困難(Mockito 標準ではモック不可、PowerMock や mockito-inline で対応)。可能ならインスタンスメソッドにして DI で差し替えられるように。

Q: static finalfinal static の違いは?
A: 順序は任意で同じ意味。慣習的に static final の順。public static final で「クラス定数」。

Q: PHP の static:: は?
A: 遅延静的束縛 (Late Static Binding)。self:: は宣言クラス、static:: は呼び出し元クラスを指します。継承時の挙動が変わります。