0Pricing
Java Academy · レッスン

static フィールドと定数

共有状態には static フィールドを、定数には static final を使い、static 初期化子を使用します。

「static フィールドと定数」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

staticフィールドと定数

staticフィールドはインスタンスではなくクラスに属します。そのクラスのすべてのオブジェクトで共有されます。定数はstaticとfinalを組み合わせて、クラスレベルの変更不可能な値を作成します。

staticフィールドとインスタンスフィールド

インスタンスフィールドにはオブジェクトごとに別のコピーがあります。staticフィールドには、そのクラスのすべてのオブジェクトで共有されるコピーが1つだけあります。

class Counter {
    private static int totalCount = 0;  // shared across all instances
    private int instanceId;              // unique per instance

    Counter() {
        totalCount++;
        instanceId = totalCount;
    }

    static int getTotalCount() { return totalCount; }
    int getInstanceId()        { return instanceId; }
}

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

System.out.println(Counter.getTotalCount()); // 3
System.out.println(c1.getInstanceId());       // 1
System.out.println(c3.getInstanceId());       // 3

static finalによる定数

定数はpublic static finalとして宣言します。慣例として、名前にはSCREAMING_SNAKE_CASEを使用します。

class MathConstants {
    public static final double PI      = 3.141592653589793;
    public static final double E       = 2.718281828459045;
    public static final double GOLDEN  = 1.618033988749895;
    public static final int    PRIMES[] = {2, 3, 5, 7, 11, 13};
}

// Access without an instance
System.out.println(MathConstants.PI);

// Constants on domain classes
class HttpStatus {
    public static final int OK        = 200;
    public static final int NOT_FOUND = 404;
    public static final int SERVER_ERR = 500;
}

static初期化ブロック

定数の初期化に複雑な処理が必要な場合は、クラスがロードされたときに1回だけ実行されるstatic初期化ブロックを使用します。

import java.util.*;

class Config {
    public static final Map<String, String> DEFAULTS;

    static {
        Map<String, String> map = new HashMap<>();
        map.put("timeout",  "30");
        map.put("maxRetry", "3");
        map.put("logLevel", "INFO");
        DEFAULTS = Collections.unmodifiableMap(map);
    }
}

System.out.println(Config.DEFAULTS.get("timeout")); // 30

staticカウンターパターン

staticフィールドは、IDの生成、メトリクスのカウント、共有キャッシュなどによく使用されます。

import java.util.concurrent.atomic.AtomicLong;

class Order {
    private static final AtomicLong ID_SEQUENCE = new AtomicLong(1000);

    private final long id;
    private final String item;

    Order(String item) {
        this.id   = ID_SEQUENCE.getAndIncrement();
        this.item = item;
    }

    long getId()   { return id; }
    String getItem() { return item; }
}

Order o1 = new Order("Laptop");
Order o2 = new Order("Mouse");
System.out.println(o1.getId()); // 1000
System.out.println(o2.getId()); // 1001

staticフィールドによるSingleton

Singletonでは、staticフィールドに単一のインスタンスを保持します。常に必要とは限らないクラスには、遅延初期化を使用します。

class DatabasePool {
    private static volatile DatabasePool instance;
    private final int maxConnections;

    private DatabasePool() { this.maxConnections = 20; }

    public static DatabasePool getInstance() {
        if (instance == null) {
            synchronized (DatabasePool.class) {
                if (instance == null)
                    instance = new DatabasePool();
            }
        }
        return instance;
    }

    public int getMaxConnections() { return maxConnections; }
}

System.out.println(DatabasePool.getInstance().getMaxConnections()); // 20

staticインポート

import staticを使うと、クラス名の接頭辞なしでstaticメンバーを使用できます。定数やユーティリティメソッドに便利です。

import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
import static java.lang.Math.pow;

// Without import static: Math.PI * Math.pow(r, 2)
double radius = 5.0;
double area = PI * pow(radius, 2);
System.out.printf("Area: %.2f%n", area); // 78.54

// Caution: overuse of static imports hurts readability
// Acceptable for: Math.*, Assert.* in tests, TimeUnit

staticフィールドのスレッドセーフティ

複数のスレッドで共有するstaticフィールドには、競合状態を避けるために同期化またはアトミック型が必要です。

import java.util.concurrent.atomic.*;

class RequestMetrics {
    private static final AtomicLong requestCount  = new AtomicLong(0);
    private static final AtomicLong totalLatencyMs = new AtomicLong(0);

    public static void record(long latencyMs) {
        requestCount.incrementAndGet();
        totalLatencyMs.addAndGet(latencyMs);
    }

    public static double averageLatency() {
        long count = requestCount.get();
        return count == 0 ? 0 : (double) totalLatencyMs.get() / count;
    }
}
RequestMetrics.record(45);
RequestMetrics.record(120);
System.out.println(RequestMetrics.averageLatency()); // 82.5

可変staticフィールドの落とし穴

可変staticフィールドは危険です。グローバルな可変状態はテストが難しく、適切に扱わなければスレッドセーフではなく、クラス間に隠れた結合を生み出します。

// BAD: mutable static state
class GlobalConfig {
    public static String environment = "dev"; // mutable global!
}
// Any code anywhere can change GlobalConfig.environment
// Very hard to test, unexpected interactions

// BETTER: immutable constant
class GlobalConfig2 {
    public static final String ENVIRONMENT =
        System.getenv().getOrDefault("APP_ENV", "dev");
}

// BEST: inject via constructor (dependency injection)
class Service {
    private final String environment;
    Service(String environment) { this.environment = environment; }
}

定数インターフェースのアンチパターン

インターフェースに定数を保持させる方法(Constant Interfaceアンチパターン)は推奨されません。代わりに、privateコンストラクタを持つクラスを使用します。

// BAD: constant interface — pollutes the namespace of implementing classes
interface FinancialConstants {
    double TAX_RATE = 0.08;  // implicitly public static final
}

// GOOD: utility class for constants
final class FinancialConstants2 {
    private FinancialConstants2() {} // prevent instantiation

    public static final double TAX_RATE  = 0.08;
    public static final double VAT_RATE  = 0.20;
    public static final int    MAX_ITEMS = 100;
}
System.out.println(FinancialConstants2.TAX_RATE); // 0.08

実践:定数によるフィーチャーフラグ

static final boolean定数をコンパイル時のフィーチャーフラグとして使用します。JITコンパイラによって不要な分岐が除去されます。

class Features {
    public static final boolean ENABLE_ANALYTICS   = true;
    public static final boolean ENABLE_AI_SEARCH    = false;
    public static final boolean DEBUG_MODE          =
        "true".equals(System.getenv("DEBUG"));
}

// The JIT eliminates this if-block when ENABLE_AI_SEARCH is false:
if (Features.ENABLE_AI_SEARCH) {
    System.out.println("Running AI search...");
}

if (Features.DEBUG_MODE) {
    System.out.println("[DEBUG] Request received");
}

理解度チェック

staticフィールドとインスタンスフィールドの違いは何ですか?

まとめ:staticフィールドと定数

重要なポイント:

  • staticフィールドはクラスに属し、すべてのインスタンスで共有されるコピーが1つだけあります
  • 定数にはpublic static finalとUPPER_SNAKE_CASEを使用します
  • 複雑な初期化が必要な定数にはstatic初期化ブロックを使用します
  • 並行処理のコードで可変staticフィールドを使う場合は、AtomicLong/AtomicIntegerを優先します
  • 可変staticフィールドは避けます。テストが難しい隠れたグローバル状態を生み出すためです
  • 定数にはインターフェースではなく、インスタンス化できないクラス(privateコンストラクタ)を使用します

よくある質問

「static フィールドと定数」レッスンは無料ですか?

はい。「static フィールドと定数」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「static フィールドと定数」で何を学びますか?

共有状態には static フィールドを、定数には static final を使い、static 初期化子を使用します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「static フィールドと定数」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. メソッドオーバーロードの規則
  2. 可変長引数パラメーター
  3. static フィールドと定数
  4. ユーティリティクラスと static ファクトリーメソッド
← Java Academyに戻る