検索

キーワード


【Java】 イニシャライザとは?コンストラクタとの関係も解説

  • 公開日:2020-08-26 18:41:52
  • 最終更新日:2021-01-25 19:17:47
【Java】 イニシャライザとは?コンストラクタとの関係も解説

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

ここでは初学者として学習を終えた私が、アウトプットの意味も込めてイニシャライザについて紹介させていただきます。

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


関連記事リンク:コンストラクタの紹介 / クラスの紹介 / メソッド・オーバーロードの紹介 / インスタンスの紹介 / コレクション(List)の紹介 / static修飾子の紹介 / 匿名クラスの紹介 / 例外の紹介 / 反復処理の紹介

イニシャライザと staticイニシャライザ

クラスをインスタンス化するときはコンストラクタを使って「初期化」を行います。

コンストラクタでは対応できない、またはコンストラクタに書くと乱雑になる初期化処理は、

イニシャライザに書くことで問題が解決できる場合があります。

ここでは初期化に関わるイニシャライザの種類や書き方、

同じような機能を持ったコンストラクタとの違いについて紹介させていただきます。


イニシャライザとは?

「初期値」をあらかじめ意図した値に書き換えておきたい場合にイニシャライザやコンストラクタを活用します。

ここで紹介するイニシャライザには「インスタンスイニシャライザ」と「staticイニシャライザ」の2種類が存在します。

まずはイニシャライザそれぞれの違いを見ていきましょう。

 ※コンストラクタは別記事で紹介させていただきます。


インスタンスイニシャライザ

クラスのインスタンス生成時にコンストラクタと共に初期化を行うイニシャライザです。

厳密には、イニシャライザに書かれた初期値をコンストラクタへ渡して初期化を行います。

インスタンスイニシャライザがコンストラクタを経由することからわかるように、

オーバーロードしたコンストラクタを含めて、クラス内の全てのコンストラクタでイニシャライザは実行されます。

そのためコンストラクタで共通の値は、

それぞれのコンストラクタで書かずにイニシャライザにまとめるなどの使い方ができます。


イニシャライザの書き方

イニシャライザの書き方は、クラス直下に「 { } 」(ブロック)を書くだけとシンプルです。

・イニシャライザ: { 初期値 }


◆イニシャライザの書き方例

package sample;

public class InitialiserTest {

	// インスタンスフィールド
	int number;

	// インスタンスイニシャライザ
	{
		number = 2;
	}
}

InitialiserTest クラスのフィールド変数 number に対してイニシャライザで初期値を 2 にしています。

※ここではコンストラクタの宣言がないため、自動生成される「InitialiserTest()」のコンストラクタが使われています。


匿名クラスの初期化

匿名クラスの詳細は別記事にて紹介させていただきますが簡単に言うと、

使われる範囲がかなり限定されるためにクラスを作るまでもないと判断されたものに対して、

匿名クラスで対応する場合があります。

この匿名クラスはクラス名を持たないため、コンストラクタも持っていません。

このようにコンストラクタが無い場合にもイニシャライザが活躍します。


◆匿名クラスでのイニシャライザの使用例

List<String> list = new ArrayList<String>() {{int number = 1;}};

上記それぞれ分解して見てみましょう。

「List<String> list = new ArrayList<String>()」はコレクションを作成しています。

「{{int number = 1; }}」の外側の「{ }」は匿名クラス用のカッコです。

「{{int number = 1; }}」の内側の「{ }」はイニシャライザ用のカッコです。

イニシャライザのカッコ内で「int number = 1;」の初期値を設定しています。


テスト用にプログラムを書く時に、以下のような記述をする(または見掛ける)ことがあると思います。

List<String> list = new ArrayList<>() {
	{
		add("a");
		add("b");
	}
};
System.out.println(list);

この記述についても、匿名クラスでイニシャライザブロックを定義することで実現されています。


インスタンスイニシャライザでの例外

インスタンスイニシャライザはコンストラクタを経由して初期化を行うため、

インスタンス生成時に例外をキャッチすることができます。

※例外の詳しい紹介は別記事でさせていただきます。


◆インスタンスイニシャライザの例外キャッチ例

【インスタンス生成されるクラス】

public class InitExceptTest {

	{
		"".substring(1); // 1番目以降を文字列を取得
	}
}

【インスタンス生成するクラス】

public class InitExceptTest2 {

	public static void main(String[] args) {

		// インスタンス生成でエラーが出た場合に chatch する
		try {
			new InitExceptTest();
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}

文字列が0番目の空文字しか存在しないため、StringIndexOutOfBoundsException の例が投げられます。

次に紹介する staticイニシャライザは、上記のように例外を受け取る相手がいないため例外処理ができません。



staticイニシャライザ

別名「クラス初期化子」「静的初期化子」「静的ブロック」「staticブロック」などとも呼ばれます。

static にはコンストラクタがないため、一般的にはフィールドへ直接初期値を設定する方法が取られます。

ただし static なものに対して、コンストラクタへ記述するような初期化を行う場合

(フィールドでは対処できない長い記述)にブロック単位で処理内容を書くことができるのが

static イニシャライザです。

※static について詳しくは別記事で紹介しますが、

 インスタンス生成をしなくてもメソッドやフィールドなどが使える特徴を持っています。


staticイニシャライザの書き方

staticイニシャライザはブロックに「static」を付けるだけと、こちらもシンプルです。

・staticイニシャライザ: static { 初期値 }


◆ staticイニシャライザの書き方例

public class InitiariserTest {

	// staticフィールド
	static int num;

	// staticイニシャライザ
	static {
		num = 2; // num を初期値 2 に設定
	}
}

staticフィールドの num に初期値 2 を設定しています。


staticイニシャライザの動くタイミング

static の特性上 staticイニシャライザは、

staticイニシャライザが書かれたクラスへアクセスした時点で1度だけクラスの初期化を行います。

staticイニシャライザ、イニシャライザ、コンストラクタを作成して staticイニシャライザの動きを見てみましょう。


◆staticイニシャライザの動作例

【インスタンス生成されるクラス】

public class InitiariserTest {

	// staticイニシャライザ
	static {
		System.out.println("static"); // static を表示
	}

	// インスタンスイニシャライザ
	{
		System.out.println("instance"); // instance を表示
	}

	// コンストラクタ
	public InitiariserTest() {
		System.out.println("constructor"); // constructor を表示
	}
}

【インスタンス生成するクラス】

public class InitiariserTest2 {

	public static void main(String[] args) {

		new InitiariserTest(); // static, instance, constructor を表示
		new InitiariserTest(); // instance, constructor を表示
	}
}

1度目のインスタンス生成でクラスへアクセスしたことで staticイニシャライザが動作しましたが、

2度目のインスタンス生成で同じクラスへアクセスしているため staticイニシャライザは動作しません。



イニシャライザの共通部分

インスタンスイニシャライザと staticイニシャライザの共通部分も確認しておきましょう。


複数のイニシャライザ

1つのクラスに複数のイニシャライザを書くことができます。

複数のイニシャライザを書いた場合は上から順番に処理され、

同じ変数に対して初期化が書かれた場合などは最後のイニシャライザの値が初期値となります。

◆複数イニシャライザを書いた例

public class InitiariserTest {

	int number;

	{
		number = 1; // 最初に処理されるイニシャライザ
	}

	{
		number = 2; // 2番目に処理されるイニシャライザ
	}

	{
		number = 3; // 最後に処理されるイニシャライザ
	}
}

インスタンス生成時の初期値は最後のイニシャライザの初期値 3 となります。

※ static イニシャライザでも同じ処理が行われます。


動作処理(メソッド)は書けない

イニシャライザは初期化を行うブロックですので、メソッドを書くことはできません。

public class InitiariserTest {

	int number;

	{
		// イニシャライザの中でメソッドを書こうとしているためコンパイルエラー
		public int num() {
			return number = 1;
		}
	}
}

※ for文などの計算処理を書くことは可能です。


イニシャライザとコンストラクタの実行優先順位

優先順位を把握せずにイニシャライザを使うと、

クラスの呼び出しで思わぬ処理が行われる可能性があるため確認しておきましょう。

イニシャライザとコンストラクタの実行優先順位は以下となります。

 ①staticイニシャライザ

 ②インスタンスイニシャライザ

 ③コンストラクタ

サンプルコードで優先順位を確認してみましょう。


◆初期化の優先順位例

【インスタンス生成されるクラス】

public class InitiariserTest {

	// コンストラクタ
	public InitiariserTest() {
		System.out.println("コンストラクタ");
	}

	// staticイニシャライザ
	static {
		System.out.println("staticイニシャライザ 1 ");
	}

	// インスタンスイニシャライザ
	{
		System.out.println("インスタンスイニシャライザ 1 ");
	}

	// インスタンスイニシャライザ
	{
		System.out.println("インスタンスイニシャライザ 2 ");
	}

	// staticイニシャライザ
	static {
		System.out.println("staticイニシャライザ 2 ");
	}
}

【インスタンス生成するクラス】

public class InitiariserTest2 {

	public static void main(String[] args) {

		InitiariserTest test = new InitiariserTest();
	}
}

【実行結果】 以下文字列が順に表示されます。

 ① staticイニシャライザ 1

 ② staticイニシャライザ 2

 ③ インスタンスイニシャライザ 1

 ④ インスタンスイニシャライザ 2

 ⑤ コンストラクタ


もしイニシャライザとコンストラクタが同じ変数へ代入をする場合は、

最後に実行されるコンストラクタの結果が初期値となります。


◆インスタンスイニシャライザとコンストラクタから同じフィールドへデータを代入した例

public class InitiariserTest {

	// フィールド
	int num;

	// インスタンスイニシャライザ
	{
		num = 1;
	}

	// コンストラクタ
	public InitiariserTest() {
		num = 3;
	}

	// インスタンスイニシャライザ
	{
		num = 2;
	}
}
public class InitiariserTest2 {

	public static void main(String[] args) {

		InitiariserTest test = new InitiariserTest();
		System.out.println(test.num); // コンストラクタのデータ 3 を表示
	}
}


イニシャライザの代入を上書きしてコンストラクタの3が表示されました。

このように実行優先順位によっては代入が上書かれてしまうことがあるため注意が必要です。



まとめ

イニシャライザはコンストラクタ群で共通の初期化処理を行う際にまとめ役として活躍します。

また匿名クラスのようなコンストラクタを持たないクラスに対しても有効です。

実行優先順位に気を付けて活用しましょう。


関連記事リンク

コンストラクタの紹介 / クラスの紹介 / メソッド・オーバーロードの紹介 / インスタンスの紹介 / コレクション(List)の紹介 / static修飾子の紹介 / 匿名クラスの紹介 / 例外の紹介 / 反復処理の紹介


【著者】

若江

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】値?変数?型??しっかり解説!『データ型(プリミティブ型と参照型)』

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