検索

キーワード


【Java】自作クラス・自作メソッドへのジェネリクス付与方法を解説!

  • 公開日:2020-10-07 12:28:34
  • 最終更新日:2021-01-26 09:27:49
【Java】自作クラス・自作メソッドへのジェネリクス付与方法を解説!

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

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

自作クラスやメソッドへのジェネリクスの付与について紹介させていただきます。

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


関連記事リンク:ジェネリクスの基礎紹介 / static修飾子の紹介 / インターフェースの紹介 / 継承の紹介 / メソッドの紹介 / クラスの紹介

ジェネリクス(クラス・メソッド・インターフェースへの付与方法)

Java であらかじめ用意されたクラスやメソッド、インターフェースには

ジェネリクスが利用されていることもしばしば見受けられるため、

ジェネリクスでの型指定などはしたことがあるかもしれません。

しかし自分で作成したクラスなどへジェネリクスを付与するとなると、

書き方などのルールの知識が新たに必要となります。

ここでは自作クラスやメソッド、インターフェースへのジェネリクスの付与方法について紹介させていただきます。


クラスへのジェネリクス付与

ジェネリクスは Java で既存のクラスやメソッドなどによく使われるほど有用な機能です。

自作したクラスへのジェネリクスの付与ができれば、

型に対してより自由度の高いプログラムの作成が可能となります。

自作クラスへのジェネリクスの付与方法を学びましょう。

※ジェネリクスとは?といった基礎は別記事にて紹介させていただきます。


クラスのジェネリクス付与方法

クラスに対してのジェネリクスはクラス名の後に「型変数」を記述することで付与できます。

型変数の名前は一般的に「< E >」のように大文字の一文字で表現され、

受け取る型の目的に合わせて E と記述されたり T と記述されたりします。


 E: Element の略

 T: Type の略

 V: Value の略

 K: Key の略

 N: Number の略

 S: 2番目の意味

 U: 3番目の意味


これら型変数は「E型」や「T型」といった型で呼ばれますが、

型の指定があった際に、その指定された型と入れ替えられるような形で処理されるため、

「E型」や「T型」のインスタンスを生成することはできませんので注意しましょう。

※型変数の名前は大文字でなくても、また一文字でなくても設定はできますが一般的には上記のルールに従って記述されます。


サンプルコードでクラスへジェネリクスを付与した例を見てみましょう。


◆自作クラスへのジェネリクス付与例

public class GenericsTest<T> {	
}


上記例は T 型を扱うクラスです。

GenericsTest クラス内のフィールドやメソッドにも T 型を付与すると、

クラスが受け取った型をフィールドやメソッドとも共有することができます。


◆ジェネリクスを付与した自作クラスのフィールドとメソッド例

public class GenericsTest<T> {

	T test; // T 型の値を保持するフィールド
	
	// T 型の戻り値と T 型の変数を処理するメソッド
	public T method(T test) {
		return this.test = test;
	}
}


例えば GenericsTest クラスが具体的な型として String 型を受け取ると、

T 型を指定したフィールドやメソッドの型も String 型になります。

サンプルコードで表すと以下のようなイメージです。

public class GenericsTest<String> {

	String test; // T 型が String 型へ変換される

	// T 型の戻り値と T 型の変数が String 型へ変換される
	public String method(String test) {
		return this.test = test;
	}
}


自作した T 型のクラスに String 型を指定してインスタンス化してみましょう。

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

		GenericsTest<String> sample = new GenericsTest<String>();
		sample.method("a");

		System.out.println(sample.test);
	}
}


GenericsTest インスタンスのフィールドから文字列を取り出せました。

ちなみに型はカンマで区切ることで「T 型と E 型」のように複数指定することも可能です。


◆複数の型変数を設定する例

【作成クラス】

public class GenericsTest<T,E> {

	T testT; // T 型の値を保持するフィールド
	E testE; // E 型の値を保持するフィールド

	// T 型を扱うメソッド
	public T methodT(T testT) {
		return this.testT = testT;
	}

	// E 型を扱うメソッド
	public E methodE(E testE) {
		return this.testE = testE;
	}
}

【実行クラス】

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

		GenericsTest<String, Integer> sample = new GenericsTest<String, Integer>();

		sample.methodT("a");
		sample.methodE(1);

		System.out.println(sample.testT);
		System.out.println(sample.testE);

	}
}


指定した型の順番と型変数の順番が連動しているため記述順には注意しましょう。



メソッドへのジェネリクス付与

メソッドには型宣言前にジェネリクスを記述することで付与することがきます。


◆メソッドへのジェネリクス付与例

public class GenericsTest {

	// T 型を扱うメソッド
	public <T> T methodT(T testT) {
		return testT;
	}
}


メソッドへジェネリクスを付与した場合の型変数の有効範囲はメソッド内となります。

インスタンスを生成してメソッドを利用してみましょう。

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

		GenericsTest sample = new GenericsTest();
		sample.methodT("a"); // String 型の値を渡す
	}
}


上記メソッドへ渡す値を見ると明示的な型の指定がありません。

クラスとは違いメソッドのジェネリクスは明示的な型の指定が必要とされず、値から型を判断してくれます。

(明示的に型の宣言も可能です)


◆明示的な型宣言の例

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

		GenericsTest sample = new GenericsTest();
		sample.<String>methodT("a"); // 明示的に String 型を指定
		sample.<Integer>methodT(1); // 明示的に Intger 型を指定
	}
}



インターフェースへのジェネリクス付与

インターフェースへジェネリクスを付与した場合は、実装時に型の指定を行います。

記述場所や、メソッドへの型変数の付与の仕方はクラスと同じです。


◆インターフェースへのジェネリクス付与と実装例

【インターフェース】 T型のメソッドを1つ作成

public interface GenericsInterface<T> {
	public void method(T t);
}

【実装クラス】 String 型を指定してクラスへ上記インターフェースを実装

public class GenericsImpl implements GenericsInterface<String> {
	public void method(String str) {
		System.out.println(str);
	}
}

【インスタンス生成クラス】 インターフェースを原型としたインスタンスの生成

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

		GenericsInterface<String> test = new GenericsImpl();
	}
}


インスタンス生成で GenericsImpl (右側)はクラスのコンストラクタであり、

クラスにはジェネリクスを利用していないため「<>」の記述が付きませんので注意しましょう。


例では String 型の指定をしたインターフェースを実装しましたが、

もちろん扱う型を Integer 型や Double 型などへ置き換えることも可能です。

public class GenericsImpl implements GenericsInterface<Double> {
	public void method(Double dou) {
		System.out.println(dou);
	}
}
public class Test {
	public static void main(String[] args) {

		GenericsInterface<Double> test = new GenericsImpl();
	}
}



ジェネリクスで付与できないもの

型変数には以下のものを付与することができないため注意しましょう。

.class: 実行時に具体的な型と入れ替わるため、クラスの生成はできません。

new: クラスの生成ができないため、型変数からインスタンスの生成もできません。

instanceof: クラス生成ができないため、クラスの評価ができません。


また static なものは普遍的な性質を持つなどの特徴から、

static なものの中で型変数を使うことができませんのでジェネリクスを利用する際は気をつけましょう。



まとめ

自身で作成したクラスやメソッドなどへジェネリクスを付与できれば、

より実用的なコードの書けるエンジニアへ一歩近ずけます。

ぜひジェネリクスを理解して自作クラスやメソッドなどにも付与できるようになりましょう。


関連記事リンク

ジェネリクスの基礎紹介 / 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】値?変数?型??しっかり解説!『データ型(プリミティブ型と参照型)』

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