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()); // 3static 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")); // 30staticカウンターパターン
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()); // 1001staticフィールドによる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()); // 20staticインポート
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, TimeUnitstaticフィールドのスレッドセーフティ
複数のスレッドで共有する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フィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- メソッドオーバーロードの規則
- 可変長引数パラメーター
- static フィールドと定数
- ユーティリティクラスと static ファクトリーメソッド