Javaを学ぶ上で避けて通れないのが、static
キーワードです。
static
はクラス全体で共有される変数やメソッドを定義するために使われるキーワードで、このキーワードの使い方を学習することでクラスやインスタンスの動作原理/Javaにおけるメモリ管理の仕組みまで理解が進むようになります。

この記事では、Java初心者でも理解できるように、static
の使い方とその背後にある動作原理をステップバイステップで解説します。
Java static修飾子の基本
static
は、クラス(反対:インスタンス)に属するメンバーを定義するためのキーワードです。(※メンバーとはクラスの中に定義される要素のこと。)
メンバーの種類 | 説明 | 例 |
---|---|---|
フィールド | クラスやインスタンスのデータを保持する変数 | String name; (インスタンス用)static int count; (クラス全体で共有) |
メソッド | クラスやインスタンスで使われる処理 | void run() (インスタンス用)static void show() (クラス名で呼び出し) |
通常、オブジェクト指向言語では、インスタンス(参考 クラスとインスタンス)ごとに変数やメソッドが存在します。しかし、static
を使うと、クラス全体で共有されるメンバーを作成することができます。仮にクラスが「学校」だとすると、通常の変数は「生徒1人ひとりの持ち物」、static
変数は「学校全体で共有する校則」のようなものだと説明することができるかもしれません。
いずれにせよ、staticを理解するためには、まずはクラスとインスタンスの関係の理解が必須となります。逆に言えば、クラスとインスタンスの違いさえ分かっていればここまでの説明でstaticの意味や使い方はある程度理解できるはずです。もし、まだピンと来ていない方は↓のページをご覧ください。
ポイント1 通常の変数やメソッド
- インスタンスごとに持つもの。例えば、「車」クラスのインスタンスであるカローラとプリウスはそれぞれ別々の色を持ちます。インスタンスを作るたびにメモリに割り当てられます。
ポイント2 static
変数やメソッド
- クラス全体で共有するもの。例えば、車クラス全体で共通の情報(セダン/SUV・・・)を持つときに使います。
- クラスが最初に使われるとき(例えば、最初のインスタンスが作られるとき)に一度だけメモリに割り当てられます。その後、どのインスタンスからでも同じメモリを共有します。
- Qクラスとインスタンスの違いは?
- A
- クラス: 車の設計図のようなもの。車の特性(例えば、メーカーやモデル)や動作(例えば、走るや止まる)を定義します。
- インスタンス: クラスに基づいて作られる実際の「もの」。車クラスから作られた具体的な車(カローラやプリウス)がインスタンスです。
static修飾子の利用シーン
static
はフィールド、メソッドに加えて、ブロックの3つで使われます。ここからは具体的な利用シーンについて1個1個サンプルコードを用いながらその動作原理を解説していきます。
利用シーン | 概要 | 例 |
---|---|---|
フィールド | クラス全体で共有するデータを持たせたいときに使います。インスタンスごとではなく、1つの変数を全体で使い回します。 | static int totalCars; (全ての車の数を管理) |
メソッド | インスタンスを作らなくても、クラスから直接使いたい処理に使います。 | static void printInfo() (共通情報を表示するメソッド) |
ブロック | クラスが初めて使われたときに一度だけ実行したい初期化処理に使います。 | static { System.out.println("初期化完了"); } |
static変数の使い方
static
変数は、クラス全体で1つだけ存在する変数です。通常のインスタンス変数は各オブジェクトが個別に持ちますが、static
変数は全てのオブジェクトで共有されます。
例としてクラスを「自動車メーカー」、オブジェクトを「個々の車」と考えてみましょう。インスタンス変数は各車が持つ「カラー」や「エンジンタイプ」のようなものです。一方、static
変数はメーカー全体で共有する「生産台数」のようなもので、メーカー全体/メーカー共通で保持する変数になります。
staticフィールドの宣言方法
public class Car { static String brand = "トヨタ"; // static変数の宣言 String color; // インスタンス変数の宣言 public Car(String color) { this.color = color; } }

上記ではstatic
キーワードを使って、brand
というクラス全体で共有される変数を宣言しています。「色」は車個別ですが、ブランド名はそれらすべての車に共通するプロパティのため、static
キーワードの利用が適切です。
staticフィールドへのアクセス方法
- クラス名で直接アクセス
public class Car { static String brand = "トヨタ"; // static変数の宣言 String color; // インスタンス変数の宣言 public Car(String color) { this.color = color; } } System.out.println(Car.brand); // 出力: トヨタ
- インスタンスからもアクセス可能
public class Car { static String brand = "トヨタ"; // static変数の宣言 String color; // インスタンス変数の宣言 public Car(String color) { this.color = color; } } Car myCar = new Car("赤"); System.out.println(myCar.brand); // 出力: トヨタ

上記のコード:static
変数はクラスに属するので、myCar.brand
と書いても動作しますが、JVMは内部的に Car.brand
に置き換えて扱います。実際、Javaの文法上はインスタンスからアクセス可能ですが、意味的には「クラスからアクセスしている」と解釈されます。
つまりこのコードの最後の行は以下のように解釈される、と理解しておきましょう。
System.out.println(Car.brand);
static
変数は、プログラムの実行開始時にメモリ上に1つだけ確保されます。全てのインスタンスでこの1つの変数を共有するため、値の変更は全てのインスタンスに影響します。
システム的な視点
- メモリ領域:
static
変数はメモリの「メソッドエリア」に配置されます。この領域は、クラス情報やstatic
メンバーが保存される場所です。
動作原理をサンプルコードで
public class Sample { // staticフィールド(クラス全体で1つだけ存在する) static int count = 0; // コンストラクタが呼ばれるたびにcountを増やす public Sample() { count++; System.out.println("インスタンス生成!現在のcount = " + count); } public static void main(String[] args) { // インスタンスを3つ作る Sample a = new Sample(); // → countは1になる Sample b = new Sample(); // → countは2になる Sample c = new Sample(); // → countは3になる // どのインスタンスから見てもcountは同じ System.out.println("a.count = " + a.count); // → 3 System.out.println("b.count = " + b.count); // → 3 System.out.println("c.count = " + c.count); // → 3 // クラス名からもアクセスできる(推奨) System.out.println("Sample.count = " + Sample.count); // → 3 } } /* 出力結果 インスタンス生成!現在のcount = 1 インスタンス生成!現在のcount = 2 インスタンス生成!現在のcount = 3 a.count = 3 b.count = 3 c.count = 3 Sample.count = 3 */

↑のコードから、static
フィールドは「インスタンスごと」ではなく「クラス全体で1つ」だけ保持されることが分かります。
staticメソッドの使い方
static
メソッドは、インスタンスを生成しなくてもクラス名で直接呼び出せるメソッド(クラス全体で定義されているメソッドなので)です。
例え話:自動車メーカーが提供する「ブランド紹介ページ」のようなものです。特定の車(インスタンス)を持っていなくても、誰でもメーカー(クラス)のブランド情報(static
メソッド)を見ることができま
staticメソッドの宣言方法
public class Car { static String brand = "トヨタ"; static void showBrand() { // staticメソッドの宣言 System.out.println("この車のブランドは " + brand + " です。"); } }
staticメソッドへのアクセス方法
- クラス名で直接呼び出し
public class Car { static String brand = "トヨタ"; static void showBrand() { // staticメソッドの宣言 System.out.println("この車のブランドは " + brand + " です。"); } } Car.showBrand(); // 出力: この車のブランドは トヨタ です。
staticブロックとは?その役割
static
ブロックは、クラスがロードされるときに一度だけ実行されるコードブロックです。初期設定や複雑な初期化処理が必要な場合に使用します。
※コードブロックとは、複数の処理を{ }で囲んだ部分のことです。Javaでは、ブロック内に書かれたコードが順に実行されます。
staticブロックの宣言方法
public class Car { static String brand; static { // staticブロック内での初期化 brand = getBrandFromConfig(); } static String getBrandFromConfig() { // ここでは固定値を返します return "トヨタ"; } }
staticブロックのポイント
- クラスが初めてロードされたときに一度だけ実行されます(
new
でインスタンスを作らなくても実行されます)。 - 複数のstaticブロックがある場合は、上から順に実行されます。
- static変数の初期化や設定ファイルの読み込みなどに使われます。

staticブロックについては、以下のページにてさらに詳しく1から解説しております。是非最後までご覧ください。
システム観点から見るstaticの動作原理
これまでの解説で基本は終了です。が、ここからはより詳しくstaticの動作原理を深堀して解説していきます。
メモリとクラスローダー
Javaではプログラム実行時に必要となったタイミングでクラスファイルを読み込んで実行していきます。これを「ロード」と呼びます。このとき、クラスファイルの中身はstaticメンバーとそれ以外とで格納されるメモリ領域に違いがあります。

メモリ領域の理解
- static領域:
static
変数やメソッド、クラスの情報が保存される領域。 - ヒープ領域:インスタンス(オブジェクト)が保存される領域。
ポイントは、staticメンバーはインスタンスが保存される領域とは別の部分に格納されるということ。そして、この分離格納はロード後すぐのタイミングで行われるという点(=なので、staticメンバーはインスタンスを作らなくても利用できるようになるということです。)
クラスローダーの役割
- クラスローディング:JVM(Java仮想マシン)が必要なクラスをメモリに読み込むプロセス。
- ロードのタイミング:クラスが初めて使用されるとき。
staticの動作フロー
- クラスのロード:JVMが
Car
クラスをメモリに読み込みます。 - staticブロックの実行:クラスがロードされる際に
static
ブロックが一度だけ実行されます。 - staticメンバーの利用可能:
static
変数やメソッドが使用可能になります。
例え話で理解:
- 新しい車種(クラス)を生産するために、メーカーが工場を設立するイメージです。
- クラスのロード:工場の設立。
- staticブロックの実行:工場の初期設定や機械の調整。
- staticメンバーの利用可能:車の生産開始。
staticを使うメリット
static
キーワードを使うことで、クラス全体で共有するデータやメソッドを定義することができるようになる←これが1番のメリットで、この結果メモリの効率化やコードの簡潔さが向上します。
参考 メモリとは?
メリット1:メモリの効率化
static
変数やメソッドは一度だけメモリに割り当てられ、全てのインスタンスで共有されます。これにより、同じデータを何度も作らずに済み、メモリの使用量を減らすことができます。
public class Car { public static String type = "Vehicle"; // static変数 public String model; // インスタンス変数 public Car(String model) { this.model = model; } } public class Main { public static void main(String[] args) { Car car1 = new Car("Corolla"); Car car2 = new Car("Prius"); System.out.println(Car.type); // "Vehicle" System.out.println(car1.model); // "Corolla" System.out.println(car2.model); // "Prius" } }
メリット2:インスタンスを作らずに使える
static
メソッドや変数は、インスタンスを作らずに直接クラス名を使ってアクセスすることができる←これも大きなメリットになります。
public class MathUtils { public static int add(int a, int b) { return a + b; } } public class Main { public static void main(String[] args) { int result = MathUtils.add(5, 3); System.out.println(result); // 8 } }

MathUtils.add
は、MathUtils
のインスタンスを作らずに使えます。
メリット3:共通データの管理が簡単
全てのインスタンスで共通のデータを管理する場合、static
を使うことでデータの一貫性を保ちやすくなります。例えば、あるクラス全体で共通の設定やカウンタを持たせる場合に便利です。
public class Config { public static String appName = "MyApp"; // static変数 } public class Main { public static void main(String[] args) { System.out.println(Config.appName); // "MyApp" // 別の場所で変更しても全てに反映される Config.appName = "NewAppName"; System.out.println(Config.appName); // "NewAppName" } }
Config.appName
はどこからでもアクセス可能で、一度変更すれば全てに反映されます。

static
キーワードを使うことで、メモリの効率化、インスタンスを作らずに使える便利さ、共通データの一貫した管理が可能になる、という点がポイントです。