Javaのジェネリクスのサンプルです。
目次
説明 | ジェネリクス(Generics)とは |
サンプル | ジェネリクスを使用したクラスのサンプル |
ジェネリクスを使用したメソッドのサンプル | |
型パラメータに制限をつけるサンプル(extends) | |
ワイルドカード(?) | |
ワイルドカード(?)に制限をつける(extends/super) |
ジェネリクス(Generics)とは
ジェネリクス(Generics)とは、任意のデータ型を指定できる機能のことです。
OracleのJavaのHashMapクラスのページには上記のように<K,V>と書いてあります。
HashMapを使用するときは、KやVにString型やInteger型などのデータ型を指定します。
- <K,V>を型パラメータといい、KとVは型変数と呼びます。
- 型変数のKとVに指定した型をコンパイル時に保証します。
→指定された型以外の値を代入するとコンパイルエラーになります。型安全と呼ばれます。 - 指定する型は、基本型ではなく参照型を指定します。
- 型変数は一般的に英字1文字で表します。(キーをKではなくAとしてもロジックは通ります)
- ジェネリクスは、総称型とも呼ばれます。
型変数 | 意味 |
---|---|
T | Type、型 |
K | Key、キー |
V | Value、値 |
E | Element、要素 |
HashMapのサンプル
Map<Integer,String> c1 = new HashMap<>();
c1.put(1,"あ");
//c1.put("A","あ"); //コンパイルエラー
1行目の変数c1のMapのK(key)にあたる型はIntegerで、V(value:値)の型はStringです。
2行目は、指定された型の値をセットしてます。
3行目は、1つめの引数がInteger型ではないのでコンパイルエラーになります。
ジェネリクスを使用したクラスのサンプル
package test1;
class Sample<T> {
T data1;
// コンストラクタ
public Sample(T data) {
this.data1 = data;
}
// メソッド
public T getData1() {
return data1;
}
}
public class Test1 {
public static void main(String[] args) {
Sample<String> s1 = new Sample<>("abc");
System.out.println(s1.getData1()); //abc
Sample<Integer> s2 = new Sample<>(123);
System.out.println(s2.getData1()); //123
// Sample<String> s3 = new Sample<>(123);
// System.out.println(s3.get());
}
}
3行目は、クラス名(Sample)の後にジェネリクス(<T>)を記述しています。
18行目は、ジェネリクスでString型を指定しています。実行できます。
21行目は、ジェネリクスでInteger型を指定しています。実行できます。
24行目は、ジェネリクスでString型を指定していますがコンストラクタの値が数値(123)のためコンパイルエラーになります。
ジェネリクスを使用したメソッドのサンプル
package test1;
public class Test1 {
public static void main(String[] args) {
System.out.println(getTest1("abc")); //abc
System.out.println(getTest1(123)); //123
}
private static <T> T getTest1(T a){
return a;
}
}
11行目は、メソッドにジェネリクスを使用しています。メソッドの場合、戻り値(T)の前にジェネリクス(<T>)を記述します。
6行目は、引数にString型を指定しています。実行できます。
8行目は、引数にInteger型を指定しています。実行できます。
型パラメータに制限をつけるサンプル(extends)
package test1;
class Sample<T extends Number> {
T data1;
// コンストラクタ
public Sample(T data) {
this.data1 = data;
}
public void setData1(T data1) {
this.data1 = data1;
}
}
public class Test1 {
public static void main(String[] args) {
Sample<Integer> s1 = new Sample<>(123);
// Sample<Integer> s2 = new Sample<>("123");
s1.setData1(456); //
// s2.setData1("456"); //
}
}
※NumberクラスのサブクラスにIntegerクラスがあります。
3行目は、extendsを使用して型はNumberクラスまたはNumberのサブクラスという制限をつけています。
18行目と22行目の引数の値は数値のためエラーになりません。
20行目と24行目の引数の値は文字列型のためコンパイルエラーになります。
ワイルドカード(?)
ワイルドカード(?)は、コンパイル時に型が不明であることを意味します。何の型かは、実行するときわかります。ジェネリクスと併用できることが利点です。
package test1;
class Sample<T> {
T data1;
// コンストラクタ
public Sample(T data) {
this.data1 = data;
}
}
public class Test1 {
public static void main(String[] args) {
Sample<?> s1 = new Sample<>("abc");
Sample<?> s2 = new Sample<>(123);
}
}
14行目の引数の値は文字列型です。エラーになりません。
16行目の引数の値は数値型です。エラーになりません。
ワイルドカードに制限をつける(extends/super)
package test1;
class Sample<T> {
T data1;
// コンストラクタ
public Sample(T data) {
this.data1 = data;
}
}
public class Test1 {
public static void main(String[] args) {
// extends
Sample<? extends Integer> s1 = new Sample<>(123);
// Sample<? extends Integer> s2 = new Sample<>(123.1);
Sample<? extends Number> s3 = new Sample<>(123.1);
// super
Sample<? super Integer> s4 = new Sample<>(123.1);
Sample<? super Number> s5 = new Sample<>(123.1);
}
}
※NumberクラスのサブクラスにIntegerクラスがあります。
15行目のジェネリクスは、extendsを使用してIntegerクラスまたはIntegerのサブクラスを指定しています。実行できます。
17行目のジェネリクスの指定は15行目と同じですが、引数が小数点の数値のためコンパイルエラーになります。
19行目は、NumberクラスまたはNumberのサブクラスを指定しています。実行できます。
22行目は、superを使用してIntegerクラスまたはIntegerのスーパークラスを指定しています。そのため引数が小数点の数値ですが実行できます。
24行目は、NumberクラスまたはNumberのスーパークラスを指定しています。実行できます。
関連の記事