検索

キーワード


【Java】 static の意味や特徴を解説!static修飾子の使用方法も

  • 公開日:2020-09-15 13:18:39
  • 最終更新日:2021-01-28 13:24:55
【Java】 static の意味や特徴を解説!static修飾子の使用方法も

こんにちは、駆け出しプログラマーの若江です!

ここでは初学者として学習を終えた私からアウトプットの意味も込めて、

static 修飾子について紹介させていただきます。

できる限り初学者が理解しやすい内容として紹介させていただくので、参考となれば幸いです!


関連記事リンク:インターフェースの紹介 / 変数と定数の紹介 / メソッドの紹介 / インスタンスの紹介 / アクセス修飾子の紹介 / final 修飾子の紹介 / クラスの紹介


static修飾子 ~static領域の特徴と注意すべき点~

Java のクラスはインスタンスを生成する機能の面と、

static 領域を持つ面、2つの側面を持っています。

ここではその中でも static について詳しく紹介させていただきます。


static とは

static とはクラス自体に属するメンバ(変数(フィールド)やメソッドなど)を指します。

和訳すると「静的な」や「動かない」のような意味になり、

static が「静的」であれば、インスタンスは対象的に「動的」と言えます。

それは static なものはインスタンス生成されないという点と、

1つのクラスから生成された複数のインスタンスに対して共通のデータを提供することができるという点から、

static が(データの書き換えなどがされなければ)普遍的な存在となるためです。

static の特徴を理解することで 、そのメリットを知ることができます。


static 修飾子

まず static はクラス内の変数やメソッドなどに static 修飾子を付けることで扱うことができます。

static 修飾子を記述する場所は変数、メソッドの型宣言前であれば不問ですが、一般的な場所は以下です。

・static の基本構文(メソッドの場合):

 アクセス修飾子 static 戻り値の型 メソッド名(引数の型 引数名){ 処理内容 }; 

・static の基本構文(フィールドの場合):

 アクセス修飾子 static 変数の型 フィールド名;

※アクセス修飾子の有効範囲は通常のものと同じです。


static 修飾子が付与されたものは、

「static ~」や「static な~」「静的な~」などと呼ばれるようになります。

これに対して static 領域に分類されないものは「非static ~」や「static でない~」などと呼ばれます。


ちなみに、アクセス有効範囲が public な「static 変数」は「グローバル変数」とも呼ばれます。

public で static な変数は広域で利用することができることがその由来となっています。



static の特徴

インスタンス生成されない特徴

クラスはインスタンスを生成するためのデータを保持すると同時に、

別途クラス自身がデータを保持するための空間を持ちます。

このクラス自身がデータを保持する空間を static 領域と呼びます。

static 領域に含まれるデータはインスタンス化されません。

インスタンス化を必要としないため、

クラス名.メソッド名」や「クラス名.フィールド名」のような呼び方で、クラスから直接呼ぶことができます。

また、上記のようにクラス名を指定してメソッドや変数を呼ぶことから、

static なメソッドは「クラスメソッド」、static な変数は「クラス変数」とも呼ばれます。


◆ static フィールドの作成と呼び出し例

【クラス①】 static フィールドで 1 を保持

public class StaticTest {

	public static int num = 1;
}

【クラス②】 インスタンス生成なしでクラス①から直接 static フィールドを呼び出し

public class Test {
	public static void main(String[] args) {

		System.out.println(StaticTest.num); // 結果:1 を表示
	}
}


ちなみに static なものを持つクラス内、もしくは継承関係にあるクラス内では、

クラス名を省略して書くことができます。

◆ static フィールドの呼び出し例 ( 継承/クラス名省略 )

【親クラス】 static フィールドの作成

public class StaticTest {

	public static int num = 1;
}

【子クラス】 static メソッドでクラス名を書かずに親クラスの static フィールドを呼び出し

public class StaticTest2 extends StaticTest{

	public static void method() {
		System.out.println(num);
	}
}

【実行クラス】 インスタンス生成なしで子クラスの static メソッドを呼び出し

public class Test {
	public static void main(String[] args) {

		StaticTest2.method(); // 結果:1 を表示
	}
}


インスタンス生成をしていないため、かなりスッキリとした呼び出し方ができます。

この点ではコーディングの負担を軽減でき、可読性を上げられるメリットを持っています。


1つのクラスから生成されたインスタンスは static を共有する特徴

1つのクラスから生成された複数のインスタンスにおいて、static の情報は共有されます。

例えば、クラスA を複数インスタンス化します。

クラスA のインスタンス群は当然渡された値に応じてそれぞれ異なる結果を返します。

対して static はそれら複数のインスタンスに対して共通の結果を返します。

もし static のデータに何らかの変更が加えられた場合も同様に、全てのインスタンスに共有されます。


◆インスタンスと static のフィールド比較

【クラス①】 「static フィールド」と、static フィールドの値「確認用メソッド」「更新用メソッド」の作成

public class StaticTest {

	public static int number = 0;

	// static フィールドの値を確認するメソッド
	public void check() {
		System.out.println(number); 
	}

	// static フィールドの値を更新するメソッド
	public void change(int num) {
		number = num;
	}
}

【クラス②】 インスタンス1とインスタンス2 で static フィールドの値が共有されていることを確認

public class Test{
	public static void main(String[] args) {

		// インスタンス1
		StaticTest test = new StaticTest();
		test.check(); // static フィールドの値を確認 = 0 を表示

		// インスタンス2
		StaticTest test2 = new StaticTest();
		test2.change(5); // static フィールドの値を更新

		// インスタンス1 と インスタンス2 の値を確認
		test.check(); // インスタンス1から static フィールドの値を再度確認 = 5 を表示
		test2.check(); // インスタンス2から static フィールドの値を確認 = 5 を表示
	}
}


例のようにインスタンス1と2で static フィールドの持つ値が「0」から「5」へ更新され、共有されています。

static な変数やメソッドは共有される特徴を持つため、

同じ値を共有したい場合や同じ処理を共有したい場合に static を使うことができます。


static の注意点

static を使用するにあたっては以下の点に注意しましょう。


アクセス

非static なものから static なものへのアクセスは可能ですが、

その逆、 static なものから 非static なものへのアクセスができません。

◆ static メソッドから 非static フィールドへアクセス不可の例❌

public class StaticTest {

	public int num = 0;

	public static void method() {
		System.out.println(num); // num でエラーとなる
	}
}


共有化

static の特徴として先述した共有ですが、上記で紹介した通りインスタンスからアクセスができます。

static が持つ値の変更ができることを意味するため、誤って static が持つデータに変更があった場合、

そのデータを利用している全てのものに影響を与えます。

先述の共有の例のような、static フィールドの「0」から「5」への変更が意図したものではなかった、

といったことが起こりかねないため注意が必要です。


初期化

static なものはクラスへアクセスすることで動き始めます。

ただし1度の実行中で初期化は1度だけ行います。

そのため、複数回初期化を行う処理などはできません。


クラス内での命名重複不可

オーバーロードを除く 非static なもの同士の命名の重複ができないように、

static なもの同士の命名で重複は許可されていません。

また 非static なものと static なものの関係でもそれは同じです。


◆ 非static フィールドと static フィールドの命名重複不可例❌

public class StaticTest {

	public int num = 0; // 命名重複のためエラー
	public static int num = 0; // 命名重複のためエラー

}


継承されない

親クラスに書かれた static なものは、子クラスへ継承されません。

そのため親クラスの static なものと同じ名前のものを、子クラスで持つ事も可能です。

例えば、親と子両方で同名の static フィールド「a」を持つ事ができます。


◆親と子で同名の static フィールドを持つ例

【親クラス】 親クラスで static フィールド num を作成

public class StaticTest {

	public static int num = 0;

}

【子クラス】 子クラスで親クラスと同じ名前の static フィールド num を作成

public class StaticTest2 extends StaticTest{

	public static int num = 0;

}


上記例は、「StaticTest.num」と「StaticTest2.num」で区別されます。


暗黙的な final

インターフェースにフィールドを作成すると暗黙的に public static final の定数となります。

インターフェースの詳しい内容は別記事でご確認ください。





static の基本的な特徴を紹介しました。

クラスとインスタンス、static の関係をイメージ図にすると以下のようになります。

◆クラスの定義(左)とインスタンス(右)とstatic(青)の関係イメージ図

static領域と非static領域のイメージ図

 ※ JVM 内部の構造を表したものではありません。


先ほどは「複数のインスタンス」で static なものは共有されるを紹介しましたが、

上記図に書いているように、外部クラスからのアクセスも可能です。

つまり static なものは1つのクラスから生成されたインスタンス間での共有に限らず、

クラス同士でも同じように共有されるということです。

※ただし、アクセス修飾子の有効範囲によってアクセスの可/不可は異なります。


◆クラス間での static フィールド共有の例

【クラス①】 static フィールドと、受け取った値をフィールドへ追加する static メソッドの作成

public class StaticTest {

	public static int number = 0;

	public static void add(int num) {
		number += num;
	}
}

【クラス②】 クラス①の static フィールドを参照するメソッド

public class StaticTest2{

	public static void method() {
		System.out.println(StaticTest.number);
	}

}

【クラス③】 クラス①の static メソッドを使って static フィールドを変更。クラス②の static メソッド呼び出し

public class Test{
	public static void main(String[] args) {

		StaticTest2.method(); // 初期値確認:0 を表示

		StaticTest.add(1); // static フィールドへ 1 追加
		StaticTest2.method(); // 2回目の確認:1 を表示

		StaticTest.add(1); // static フィールドへ更に 1 追加
		StaticTest2.method(); // 3回目の確認:2 を表示

	} 
} 


static 領域へアクセスしたものへ平等に情報を提供するのが static の性格ですね。

アクセス修飾子を public にすると、例えパッケージ外のクラスでも static なものへのアクセスが可能です。

プロジェクト全体で static なものを共有することが可能なため先でお話ししたように、

public な static 変数は「グローバル変数」と呼ばれています。


余談

static な変数は final 修飾子を付けることで定数にすることができます。

定数について興味のある方は final 修飾子もしくは定数の紹介記事をご一読ください。



まとめ

static なものはインスタンスの有無に関わらず広範囲でアクセスできることができます。

今回紹介した static 変数(フィールド)や static メソッドの他にも、static クラスがあります。

static クラスを紹介するにはインナークラスの理解が必要なため、

インナークラスの紹介と併せて別記事にて紹介させていただきます。


関連記事リンク

インターフェースの紹介 / 変数と定数の紹介 / メソッドの紹介 / インスタンスの紹介 / アクセス修飾子の紹介 / final 修飾子の紹介 / クラスの紹介


【著者】

若江

30代で異業種となるIT業界へ転職した駆け出しのプログラマです。これまで主に Java や Ruby、HTML/CSS を使って学習を目的としたショップサイトや掲示板サイトの作成を行いました。プログラマとしての経験が浅いからこそ、未経験者の目線に近い形で基礎の紹介をしていきたいと思います。

よく読まれている記事
【Java】JSPでタグライブラリを使う(JSTL)

【Java】JSPでタグライブラリを使う(JSTL)

こんにちは。エンジニアの新田です!ここでは、システムエンジニアとして働いている私が、システム開発手法や開発言語について紹介していこうと思います。今回は、JSPの標準タグライブラリ「JSTL」について紹介します。Javaについて勉強している方、Webアプリケーションを構築したいと思っている方の参考になれば幸いです!関連記事リンク: 【Java】JSPの基本的な構文/【Java】JSPのアクションタグ

【Java】Stringクラス文字列を操作するメソッドの使い方まとめ!実例も紹介!

【Java】Stringクラス文字列を操作するメソッドの使い方まとめ!実例も紹介!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!そもそもStringとは何?『 String 』... Java言語において文字列のデータ型を指します。基本デ

【Java】文字列の置き換え(String#format)!エスケープシーケンスのまとめも!!

【Java】文字列の置き換え(String#format)!エスケープシーケンスのまとめも!!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!Stringクラスformatメソッドの文字列整形【java.utilパッケージ】Formatterクラスfo

【Java】文字列格納後に変更可能!?StringBufferクラスとStringBuilderクラス!

【Java】文字列格納後に変更可能!?StringBufferクラスとStringBuilderクラス!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者にも✅、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!文字列を扱う3つのクラス【java.langパッケージ】java.langパッケージの文字列を扱うクラスにはS

【Java】値?変数?型??しっかり解説!『データ型(プリミティブ型と参照型)』

【Java】値?変数?型??しっかり解説!『データ型(プリミティブ型と参照型)』

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!プリミティブ型と参照型プログラム開発では型を持った変数を使ってデータのやり取りをしますが、データ型によって仕様