はじめに
新卒サーバエンジニアのRenです。
研修でJavaを学習している際、同じMainクラス内のメソッドをmainメソッドから呼び出そうとしたところ、コンパイルエラーが発生しました。
理由は呼び出し先のメソッドにstaticをつけていなかったこと。
この機会にstaticについて調べてみたので共有します。
TL;DR
main
は「まだオブジェクトが無い状態」で呼ばれるため static- static コンテキストでは
this
が存在しない → 非-static メソッドは直呼びできずエラー- 解決策は「① 呼び出し先も static 」「② オブジェクトを生成して呼ぶ」の 2 つ
- static は便利だが乱用は設計とテストを壊す。必要条件を満たすときだけ使う
目次
- 症状の再現コードとエラーメッセージ
- static コンテキストとは?
- 解決策
- そもそも static とは何者か
- static のメリット/デメリット
- 実践での static の使いどころ 5 選
- まとめ ― “必要なときだけ static” のススメ
症状の再現コードとエラーメッセージ
public class Main {
public static void main(String[] args) {
hello(); // ← コンパイルエラー!
}
void hello() {
System.out.println("こんにちは");
}
}
error: non-static method hello() cannot be referenced from a static context
main
は呼べるのに hello
は呼べない――この謎を解く鍵が static です。
static コンテキストとは?
視点 | static コンテキスト | 非-static コンテキスト |
---|---|---|
存在するもの | クラスのみ(this なし) |
this (インスタンス参照) |
呼び出せるメソッド | static メソッド | static + 非-static |
代表例 | public static void main |
toString() , equals()
|
JVM はプログラム起動時に
- クラスをロード
-
オブジェクトを作らずに
Main.main
を呼び出す
という手順を踏みます。
つまり main
が実行される瞬間 this
は存在しない → 非-static メソッドを解決できずエラーになります。
解決策
① 呼び出し先も static にする
public class Main {
public static void main(String[] args) {
hello(); // OK
}
static void hello() { // ← クラスメソッド化
System.out.println("こんにちは");
}
}
② インスタンスを生成して呼ぶ
public class Main {
public static void main(String[] args) {
new Main().hello(); // OK
}
void hello() {
System.out.println("こんにちは");
}
}
そもそも static とは何者か
定義: インスタンス(
this
)ではなく クラスそのもの に属するメンバ。
メモリとライフサイクル
┌─ クラスロード時(1回だけ) ─────────────┐
│ メタ領域 … static フィールド/メソッド │
└──────────────────────────┘
│ (プログラム実行中)
▼
┌──────── ヒープ ────────┐
│ new Main() ごとに │
│ インスタンス領域 │
└────────────────────┘
主な性質
項目 | static | 非-static |
---|---|---|
帰属 | クラス | インスタンス |
個数 | 1 クラス 1 個 |
new するたび |
参照方法 | Main.count |
obj.count |
オーバーライド | 不可(隠蔽のみ) | 可能(ポリモーフィズム) |
static のメリット/デメリット
メリット | デメリット | |
---|---|---|
1 | インスタンス不要 → 軽量に即呼び出し | グローバル変数化で依存が散乱 |
2 | 全オブジェクト間でデータ共有 | 可変データは競合条件の温床 |
3 |
Math.max などユーティリティ API をまとめやすい |
動的ディスパッチ不可 → テストがしにくい |
4 | クラス単位で一度だけ初期化 | クラスがアンロードされるまで GC 不可 |
実践での static の使いどころ 5 選
用途 | 例 | ポイント |
---|---|---|
エントリポイント | public static void main |
JVM から直接叩かれる |
定数 | public static final String VERSION |
final とセットで不変に |
ユーティリティ関数 |
Math.sqrt , Collections.sort
|
状態を持たない純関数 |
シングルトン保持 | private static final Logger LOG |
全クラスで 1 個だけ共有 |
ファクトリメソッド |
List.of(...) (Java 9+) |
new を隠蔽し可読性向上 |
まとめ ― “必要なときだけ static” のススメ
-
main
は static コンテキスト →this
不在 → 非-static を直呼びするとコンパイルエラー。 - 解決策は
- 呼び出し先を static にする
- インスタンスを生成して呼ぶ
- static は クラス単位で共有したい振る舞い・データ に限定して使う。
- 乱用すると 密結合・テスト困難・スレッド競合など副作用が噴出するため要注意。
「そのメソッドはオブジェクト固有の状態に触れるか?」
- Yes → インスタンスメソッド
- No → static メソッド
この記事が「main と static のモヤモヤ」を晴らす一助になれば幸いです。