staticは、Javaのコードを組む際にたびたび目にするものです。しかし、決まり文句ともなっているメインメソッドで使う以外は、具体的にどのような方法で何のメリットがあってstaticを使っているのかよくわからない方もいるでしょう。
使い方を間違えると、メモリ管理や設計が効率化するどころか、逆に読みにくく煩雑になるのです。適度な利用は、コードの再利用がしやすくなるなど効率を高めます。
そこで本記事は、staticの基本知識から使い方、使いどころ、メリットなどを解説します。この記事を通してstaticを上手く利用する方法や実務に活用するための基礎を身に着けましょう。
目次
1.Javaのstaticとは
Javaのソースコードの中によく登場するのが「static」です。日本語で「スタティック」と読みます。コードを組む際に使われる修飾子の1つです。ここでは、staticの意味や種類を解説します。
staticの意味
staticには、「静的」という意味があります。静的とは、「変化しない」「静かな状態」「元の状態が維持される」などをあらわす言葉です。
対義語は「動的」で、状況に合わせて変化を続けることを指します。IT分野では、静的といった場合に、プログラムの実行時に動的な変化が起きないようにすることを意味します。
static領域とヒープ領域の違い
Javaのプログラミングでは、static修飾子を使用して、コード文に静的なクラスやメソッド、変数に変えて、メモリへのアクセスが可能となる仕組みです。
例えば、「静的変数(static Variables)」なら、システム内部で先に変数のメモリを確保し、最後まで同じ場所に変数を格納します。最後というのは「プログラム実行中ずっと」ということです。
メモリは「static領域」という非ヒープ領域に入り、一度使用されても解放されません。ヒープ領域に入った変数などとは明確に区別されるため、staticはその点で特別な修飾子です。
あくまでも、メモリ領域の格納場所が固定されるだけで、変数そのものが固定されるわけではなく、変数そのものは変えることができます。よくある誤解に、「staticが不変の固定値」という解釈をする方がいるため、最初にこれは間違った理解だと押さえておくことです。
static修飾子の種類
Javaで使われるstaticには、修飾子を付ける以下の5つの種類があります。
static クラス
static メソッド
static 変数
static final
static import
Javaのコードはクラスの中にメンバ変数を書く仕様です。種類分けは、クラスにstaticを付けるか、メソッドにstaticを付けるかなどの違いとなります。裏を返せば、staticを付ける場所によって、できることや影響を受ける場所、それに付随した機能が変わるということです。
2.Javaのstaticの使い方
以下に、5種類のstatic修飾子の使い方の基本を解説します。
staticクラス
staticクラスは、クラス内に「static class」と書くことでインスタンス化しなくても実行できるクラスのことです。
クラス内にクラスを置くことを通常、「内部(インナー)クラス」と呼び、これを使用する際には、static修飾子を利用します。
class Human { static class Name { void categorize() { System.out.println("山田花子です!"); } } }
public static void main(String[] args) { Human.Name name = new Human.Name(); name.categorize(); } } |
通常、クラスの中にクラスを入れる場合、先に外側のクラスを初期化して、その後に内部クラスをインスタンス化します。しかし、その際にstatic修飾子を使用すると、外部クラスのインスタンス化を省略することが可能です。つまり、コードの量を削減できます。
もしstaticを付けない場合は、以下のように外部・内部のインスタンス化の手続きがすべて必要です。
public class Main { public static void main(String[] args) { Language languageInstance = new Language(); Language.Java javaInstance = languageInstance.new Java(); javaInstance.categorize(); } } |
これは、staticがヒープ領域ではなく、static領域にメモリが確保されるためです。内部クラスがクラスの一部(フィールド)として扱われます。したがって、インスタンス化せずに、直接クラスのメソッドとして呼び出せるのです。
ただし、この方法には複雑化するほど管理が難しいなどのデメリットもあるため注意が必要です。
また、Javaで書くコードは、staticが内部クラスのみで使える制限付きです。外部クラスにstaticを付けてもエラーが出て実行はできません。外部クラスに書く方法は、他のプログラミング言語では使えてもJavaでは使えないのです。
staticメソッド
staticメソッドは、クラス内のメソッドにstatic修飾子を付けたものです。staticがある場合、クラスに直接所属するメソッドとなります。インスタンス(newで作成)がなくても呼び出すことが可能です。
コードを組む際に、インスタンスなしでメソッドを使用したいケースが出てくるため、そのときに活躍するのがこのstaticメソッドです。
public class Main { private static String personName = "山田花子";
personName = name; } public static String getPersonName() { return personName; }
setPersonName("田中花子"); System.out.println("現在の名前は" + getPersonName() + "です"); } } |
上記の例では、newでインスタンス化しなくてもメソッドを呼び出せていることが確認できます。ただし、staticメソッドは以下の制約があるので要注意です。
「this」キーワードが使えない
非staticなインスタンスメンバ(フィールドやメソッド)に直接アクセスできない
オーバーライドができない(継承時に注意)
static変数
static変数は、変数にstaticを付けたものです。例えば、「static int num = 10;」はstatic変数となります。static変数は「インスタンスの変数(int num = 10;)」とは異なり、クラスの全インスタンスでその値(int num = 10)が共有されます。
通常、インスタンスの変数では呼び出すごとに初期化して変更は反映されませんが、static変数ならそれが可能です。例えば、計算で10から8を引いて「10」から「2」に変更されていても、そのまま「2」という計算結果のまま使用できます。
インスタンス変数として使う場合、これが計算結果の「2」ではなく、元の「10」として使われます。このような違いがあるのです。
static final
static finalは、クラスレベルの定数を宣言するための修飾子の組み合わせです。しかし、「static final」とあえて書くことで、初期化にさらなる制限を付けることができます。
例えば、コンストラクタや通常のメソッドでの初期化はできません。書き換えはstaticメソッドのみとなります。
下記の例では、定員100人を不変にしています。そして、人数上限が来たら追加できないコードです。
public class Main { private static int totalPeople = 10; private static final int MAX_PEOPLE = 100;
if (totalPeople + count <= MAX_PEOPLE) { totalPeople += count; System.out.println("Total: " + totalPeople); } else { System.out.println("定員オーバーです。現在の人数は " + totalPeople + " 人です。"); } }
addPeople(10); addPeople(20); addPeople(80); addPeople(10); //この追加は、定員オーバー(追加不可)となる } } |
static import
static importは、クラス内ではなく、インポート宣言の場所でimportにstatic修飾子を付ける使い方です。importを付けた場合、参照に必要なコード文の記述を簡易化することができます。
import static java.util.Collections.*; import java.util.ArrayList;
public static void main(String[] args) { ArrayList<Integer> ages = new ArrayList<>(); ages.add(25); ages.add(30); ages.add(22);
System.out.println(ages); reverse(ages); //逆順 System.out.println(ages); } } |
例えば、ArrayListを使う際に「import static java.util.Collections.*;」とstaticでimportを宣言した場合、「Collections.sort() 」のメソッドは、クラス名を省略して「sort()」のみでメソッドを使えるようになります。
2つ目の逆順にするメソッドも「Collections.reverse() 」ではなく、「reverse()」だけの記述です。
ただし、コードの意味が読み取りにくくなり、クラスの違う同名メソッドがあると複雑化してエラーが起こりやすい点に注意が必要です。
関連記事
Javaのパッケージとは?クラスとの違い・分け方・命名規則・よくある分け方などわかりやすく解説
3.Javaのコードに活用したいstaticの使い道
Javaでは、staticを使う場面がいくつかあります。それを上手く活用することで、コードの効率化にもつながります。そのため、以下で使いどころを確認しましょう。
メインメソッドのエントリポイント
1つ目は、メインメソッドのエントリポイントに使用します。Javaでは特に、メインメソッドにstaticを入れることが基本となっており、「public static void main」でエントリポイントを決める仕組みです。
public class Main { public static void main(String[] args) { System.out.println("こんにちは"); } } |
エントリポイントとは、プログラム実行時に最初の開始点となる場所のことです。staticがないとインスタンスを生成してから実行する必要が出てきます。
しかし、JVM(Java仮想マシン)は、ソースコードを中間言語に変換する際に、インスタンスを作らず直接的に実行する言語仕様です。staticがない場合にインスタンスが必要になるルールと矛盾します。そのため、コンパイルはできても、その後の言語変換時にエラーが発生します。
ただし、Java21以降(2023年9月~)は、「JEP445」と呼ばれる簡略化した新しい記述方法が登場しています。教育用や初心者用といった限定的な用途と環境ではありますが、その場合はメインメソッドやエントリポイントがなくても実行できます。
もちろん、「public static void main」がJava仕様からなくなったわけではなく、内部で補完されるように優先順位とルールで補っているだけです。
System.out.println("こんにちは"); |
ユーティリティメソッド
2つ目は、ユーティリティメソッドを用意するときに使用する使い道です。ユーティリティメソッドとは、メソッドで機能をまとめて、必要に応じて呼び出して使えるメソッドのことです。
特定のクラスに依存しないため、広く計算や文字列の操作、リストや日付の処理などに使えます。コードの再利用性と設計効率化を高めたいときにおすすめです。
class StringUtils { private StringUtils() {} public static String replaceChars(String str, char char1, char char2) { if (str == null) return null;
for (char c : str.toCharArray()) { if (c == char1) { result.append(char2); } else if (c == char2) { result.append(char1); } else { result.append(c); } } return result.toString(); } }
public static void main(String[] args) { String original = "apple"; //元の文字 String swapped = StringUtils.replaceChars(original, 'a', 'o'); //入れ替え
System.out.println("文字を入れ替えた後は、" + swapped); } } |
上記のユーティリティメソッドの例では、文字を入れ替えるstaticメソッドだけ「class StringUtils」に入れています。具体的に「何を」入れ替えるかは、別のクラスに任せています。インスタンスを呼び出さずにこのような機能を使えるのです。
ファクトリーメソッド
3つ目は、staticなファクトリーメソッドの利用です。ファクトリーメソッドとは、その名の通り、オブジェクトを工場のように生産して、サブクラスでファクトリーメソッドパターンなどに使える、柔軟な処理の可能なメソッドです。
これをstatic修飾子で静的にすることで、インスタンスを生成せずにオブジェクトを繰り返し利用することができます。そのため、コードの再利用性を高めるのです。
以下は、シングルトンのソースコード例です。
class Singleton { private static final Singleton INSTANCE = new Singleton(); private Singleton() {}
return INSTANCE; }
System.out.println("インスタンスのみ"); } }
public static void main(String[] args) { Singleton singleton = Singleton.getInstance(); singleton.showMessage(); System.out.println(singleton == Singleton.getInstance()); } } |
また、ファクトリーメソッドは、サブクラスからオブジェクトを作って返す処理も可能です。エラーを返す処理でコードの管理効率を上げるなど、コンストラクタではできない用途にも使えます。
ヘルパークラス
4つ目は、staticでヘルパークラスを作って使用することです。シンプルな操作や処理・計算の機能をもたせて便利に使えます。文字列や計算、日付処理などを補助するため、コードの再利用性に貢献する使い道です。
class StringHelper { public static String reverse(String str) { return new StringBuilder(str).reverse().toString(); }
String reversed = reverse(str); return str.equals(reversed); } }
public static void main(String[] args) { System.out.println(StringHelper.reverse("こんにちは")); //逆から読む System.out.println(StringHelper.isPalindrome("しんぶんし")); //回文でtrue } } |
上記の例では、文字列操作の補助機能となる「逆から読む場合」と「回文判定」でヘルパークラスを使っています。
enum(列挙型)
enumは、Javaの型の1つで、staticを付けた複数の定数をひとまとめにした型となります。その際、クラスで一括管理することができる使い道に使えるのです。
例えば、列挙することで読みやすさが増します。以下のソースコード例では、デバッグがしやすく保守管理向けにすっきりしていることが確認できます。
enum Animal { 犬, 猫, 馬;
try { return Animal.valueOf(name); } catch (IllegalArgumentException e) { // 存在しない値が渡された場合の処理 return null; // または適切なデフォルト値を返す } } } public class Main { public static void main(String[] args) { Animal animal = Animal.fromString("犬"); System.out.println(animal); } } |
データやメモリの全体管理
上記では、ソースコード内の活用でしたが、実際にそれらの使い道は、最終的にアプリ管理やプログラム処理の効率化などに使われます。それがデータやメモリ管理の効率化です。
具体的には、staticを使うことで可能な内部クラスのフィールド化や定数の定義、ログの出力などによって、全体管理がしやすくなるのです。
以下は設定管理の例です。
class AppConfig { public static final String APP_NAME = "音楽ゲーム"; public static final String VERSION = "2.1";
public static void main(String[] args) { System.out.println(AppConfig.APP_NAME + " " + AppConfig.VERSION); } } |
アプリの設定情報に、static修飾子を付けることでアプリがどこからでも設定の値を呼び出して、全体管理に使えます。設定の値には、アプリバージョンやアプリの名称、タイムゾーン、テーマ、ログのレベル(優先度)などが可能です。
特にログのレベルは「enum」を使用することで処理が容易となり、管理の効率化につながる使い方です。
関連記事
Java 21(LTS版)完全ガイド|インストール方法、新機能の紹介、最新バージョン動向を解説
【2025年版】Javaの最新バージョン|確認方法やインストール方法を解説
4.Javaでstaticを活用するメリット
Javaでstaticを活用するメリットは次のとおりです。
メソッドの呼び出しを効率化してコード量を削減
メリットの1つ目は、staticにすることでコード量を削減できることです。staticメソッドでは、クラス名を省略できます。
そのため、余計なコードを増やさなくて済みます。もちろん、必要なときに使い、不必要なときは使わない基本は押さえつつ、メリットの高い書き方を選んでいくことが大切です。
コードを便利に再利用
メリットの2つ目は、staticを使えばメソッドや変数を再利用しやすくなることです。static変数が1つにまとめられるため、オブジェクトごとにインスタンスで値を持つ必要がなくなるのです。
そのため、全体を通じてコード量を削減できて、さらに再利用性を高めます。「もう一度同じ変数に対して別のインスタンスを使いたい」ときに便利です。
メモリの負担を減らして制御
メリットの3つ目は、メモリ管理がしやすく、コード設計によってはメモリ領域の負担を減らせることです。
先に述べたように、staticはクラスの読み込み時にstatic領域にメモリが1つだけ確保されます。1つだけ、ということはしっかり覚えておくことです。
通常は「インスタンスごとに領域を確保しては消す」という繰り返しが起こり、GC(ガベージ・コレクション)の回数も増えます。その結果、メモリの負担が増大します。しかし、staticではインスタンスごとにGC処理がされにくいため、回数による負担を抑えることができます。
5.Javaでstaticを使うデメリット・注意点
Javaでstaticを使う場合には、以下のようなデメリットや注意点があります。
乱用することでメソッドが複雑化しやすい
Javaはオブジェクト指向プログラミング言語の特徴を持っており、動的な性質が基本です。そのため、staticの静的な性質とは真逆のコードをあえて書いている形になります。しかし、staticはあくまでもJavaの中で必要に迫られて使うものです。
staticを多用すると複雑化して読みにくくなりますし、競合や他のエラーが起きやすい問題が発生する、修正範囲が拡大するなどのデメリットが大きくなります。
大規模開発で、どこまでstaticが影響しているか特定して直すのは大変な作業です。Javaのセオリーはクラスや変数にstaticを使わず、使用ポイントを絞ることです。
制約がつくため、ルールの把握が必要
staticは、通常のクラスやメソッド、変数とは異なり、細かな使用上の規則・ルールがあります。例えば、以下のようなルールは代表的です。
クラスやメソッドは継承できない
インスタンスメソッドの挙動だがインスタンスは作らない
staticとしたときに「this」が一部使えない
staticとインスタンスでメソッド名を同じ名称・並びにできない
Javaのstaticはクラスが独特で内部クラス限定となるため、継承するようなクラスがないのです。また、メソッドも継承できず、オーバーライドができません。
ただし、フィールドは継承ができます。また、例外的にサブクラスでシャドーイング(隠蔽)することも可能です。
それから、守らないとエラーになる規則ではなくても、避けたほうが良いこともあります。
例えば、staticがグローバル変数のように使われることについてですが、final以外で安易に使用するのはおすすめできません。使い方がルールの範囲内でも、Javaのstaticは多用すべきではないことにも気をつけましょう。
状況によってメモリ負荷で遅くなる
Javaのstaticはクラスで静的な内部クラスやメソッド、メンバ変数として直下のフィールドで扱います。しかし、それは実行時にインスタンスなら消えるはずの一時的なメモリが破棄されません。
staticを使いすぎることでメモリリークの発生が起こり得ます。この点に注意が必要です。もちろん、メモリリークを考慮して設計すればメモリ管理時の十分なメリットが得られます。
関連記事
Javaのオーバーライド攻略|オーバーロードとの違いや使い方・条件・戻り値などわかりやすく解説
6.Javaのstaticでよくある質問
ここでは、Java開発でクラスやメソッド、変数などにstatic修飾子を付けて利用する場合のよくある質問に回答します。
staticフィールドの初期化はいつ?
staticフィールドの初期化は、値の設定かstaticイニシャライザのどちらかで行います。staticは宣言した際にクラスが初期化されるタイミングと同じタイミングで初期化されます。
値の設定では、インスタンスのフィールドと同じタイミングで、メモリ確保と同時に1度だけ行われる仕組みです。
staticを使うべき場所はどうやって決める?
staticはメソッドや変数などの修飾子に使われるため、目的や全体設計を踏まえて付ける場所を都度決めます。付けるときのルールはあっても、始めからどの場所に付けるべきかは決まっていません。
例えば、「変数を不変とするためfinalに付ける」や「コンストラクタの代わりにインスタンスを呼ばずに使うからメソッドに付ける」など、柔軟な利用の仕方を模索することです。
staticはアクセス修飾子?
static修飾子は、「アクセス修飾子」ではなく、「非アクセス修飾子」です。アクセス修飾子は、publicやprivate、protectedなどのことです。アクセスの方法を決める修飾子を指します。
しかし、非アクセス修飾子は、基本メソッドや変数につけて、その特徴や性質を決めるための修飾子です。実際に、staticをメソッドに付けると普通のメソッドと性質が変わり、静的な性質となります。
関連記事
Javaのコンストラクタとは?コードの組み方や初期化、引数なし、オーバーロードの方法など解説
7.まとめ
今回は、Javaのコードを組む際に静的にすることを目的に使われるstaticについて取り上げました。staticは使い方次第でプログラムの使い方の幅を広げます。
主なメリットはコードを便利に再利用できる、効率化してコード量を削減可能、メモリの負担を減らして制御できるなどです。活用できる場面はあまり多くありませんが、ある程度使い道が決まっています。
そのため、必要なときに入れる意味や理由を知っておくだけで、ソースコードやメモリを効率的に管理できます。
本記事が皆様にとって少しでもお役に立てますと幸いです。
「フリーランスボード」は、数多くのフリーランスエージェントが掲載するITフリーランスエンジニア・ITフリーランス向けの案件・求人を一括検索できるサイトです。
開発環境、職種、単価、稼働形態、稼働日数など様々な条件から、あなたに最適なフリーランス案件・求人を簡単に見つけることができます。
単価アップを目指す方や、自分の得意なスキルを活かせる案件に参画したい方は、ぜひ「フリーランスボード」をご利用ください。