Javaの<>の意味を基礎から解説!|<>を正しく学んで使いこなそう

- SE
- Javaにおける<>はどのような意味なのでしょうか。
- PM
- ジェネリクスと言う機能を実現するための記号を意味します。
この記事でわかること
Javaの<>の意味は?
Javaにおける<>は、ジェネリクスと言う機能を実現するための記号を意味します。ジェネリクスの意味は、型に依存しないプログラミングを実現するための方法のことです。と言っても何のことだかわからないと思いますので、サンプルで説明しましょう。
class ObjPack {
private Object obj;
public ObjPack(Object obj) {
this.obj = obj;
}
public Object getObj() {
return obj;
}
}
まずはObjectクラスの動作を押さえる
上のJavaサンプルのObjPackクラスは、色々な型のクラスをObject型として保持して、getObjメソッドで返すという単純なものです。このクラスを以下のようにして使ってみます。
ObjPack op = new ObjPack(123);
Object o = op.getObj();
System.out.println(o.getClass());
// Integer型にキャストする
Integer in = (Integer)o;
System.out.println(in.intValue());
これを実行すると、以下のように表示されます。
class java.lang.Integer
123
int型の数値の123をObject型に代入すると、Javaのオートボクシングと言う機能でInteger型に変換されます。そのため(Integer)でキャストして問題なく利用できます。
キャストを間違えるとClassCastExceptionが発生してしまう
しかし以下のJavaサンプルのようにすると、どうなるのでしょうか。
ObjPack op = new ObjPack(123);
Object o = op.getObj();
// String型にキャストする
String st = (String)o;
System.out.println(st);
これを実行するとClassCastExceptionが発生してしまいます。Integer型なのにStringでキャストしているからです。
しかし明らかに間違っているのに、コンパイルではエラーにしてくれませんでした。もっと複雑なプログラムの場合、コンパイルの時点でこの間違いを検出するのはとても困難だからです。
型チェックを入れればとりあえずはExceptionを防げる
ClassCastExceptionを防ぐには、ObjPackを以下のように修正すればOKです。objを返す時にinstanceofで型をチェックしています。
class ObjPack {
private Object obj;
public ObjPack(Object obj) {
this.obj = obj;
}
public String getString() {
if (obj instanceof String)
return (String)obj;
else
return null;
}
public Integer getInteger() {
if (obj instanceof Integer)
return (Integer)obj;
else
return null;
}
}
ジェネリクスの<>でクラスを書き換える
しかし上のJavaサンプルのようなやり方では、対応するクラスを増やすたびにget~を追加しなければなりません。もっと簡単に様々なクラスに対応できる方法はないのでしょうか。
そこで使用するのがジェネリクスの<>です。<>を使ってObjPackを以下のように直します。
class ObjPack<T> {
private T obj;
public ObjPack(T obj) {
this.obj = obj;
}
public T getObj() {
return obj;
}
}
<>で型に依存しないクラスにできる
上のJavaサンプルのようにすることで、ObjPackを型に依存しないようにできます。これが<>のジェネリクスの意味です。このObjPackは以下のように使えます。
ObjPack<Integer> op1 = new ObjPack<Integer>(123);
Integer in = op1.getObj();
System.out.println(in.intValue());
ObjPack<String> op2 = new ObjPack<String>(“”あいう””);
String str = op2.getObj();
System.out.println(str);
ジェネリクスのクラス名には<t>を使う
上のJavaサンプルの実行結果は以下のようになります。
123
あいう
<>の中に使用するクラス名を記述することで、あらゆる型のクラスに対応できるようになっています。
<>を使う意味の基本がこれでわかったでしょうか。なおこのサンプルの<T>のTはそれ以外の文字でも良いのですが、ジェネリクスではクラス名にはTを使うことが一般的なルールとなっています。
ジェネリクスには制約をかけられる
Javaのジェネリクスの<>には制約をかけることができます。以下のサンプルをご覧ください。
class ObjPack<T extends Number> {
private T obj;
public ObjPack(T obj) {
this.obj = obj;
}
public T getObj() {
return obj;
}
}
ObjPackの<>のところにextends Numberを追加しました。これはNumberクラスのサブクラスだけが対象、という意味です。NumberクラスのサブクラスにはInteger、Short、Long、Floatなどがありますが、そういったクラスと、自分で作ったNumberクラスを継承したクラスのみが使えるという意味になるのです。
こうすることで、以下の<String>の方はエラーになります。
ObjPack<Integer> op1 = new ObjPack<Integer>(123);
ObjPack<String> op2 = new ObjPack<String>(“”あいう””);
コレクションで<>を使う
Javaで<>を実際に使うのは上のような例よりも、コレクションが多くなるでしょう。コレクションとはCollectionインターフェイスを実装した、複数のObject型のデータを保持できるクラスという意味です。
コレクションのうちの1つの、Listを使った以下のサンプルをご覧ください。なおソースの先頭には「import java.util.*;」の記述が必要です。
List list = new ArrayList();
list.add(“”あいう””);
list.add(“”ABC””);
for (String s : list) {
System.out.println(s);
}
コレクションには<>が必要になる
上のJavaサンプルは「for (String s : list) {」の箇所が「Type mismatch: cannot convert from element type Object to String」と言うエラーになります。
このサンプルの拡張for文はlistの中身を、String型の変数sとして一つずつ取り出すという意味ですが、listの中身がString型として保障されてないのでエラーになるのです。
そこでlistの宣言を以下のように<>を使用して修正しましょう。
List<String> list = new ArrayList<String>();
これでエラーはなくなり、実行結果は以下になります。
あいう
ABC
- SE
- Javaの<>の意味がよく理解できました。
- PM
- クラスの型に依存しないシンプルなプログラミングを実現するためには<>を使用すると良いでしょう。
Javaの<>の意味はジェネリクスだった
Javaの<>の意味について解説しましたが、ご理解頂けましたでしょうか。
<>はジェネリクスで使用される記号と言う意味で、クラスの型に依存しないシンプルなプログラミングを実現できる便利な機能であることが分かったのではないでしょうか。