構文
[1] ジェネリック(何も制限なし)
public class SampleA <T> { public void setName(T value) { // 略 } }
[2] 境界型 (Bounded Type)
// SampleB を生成する際は、クラス SampleA を継承したクラスと限定できる(使える!) public class SampleB <T extends SampleA> { }
extends:<? extends クラス名>
* 「このクラスの派生クラス (サブクラス) なら何でも」という指定方法 * ?記号を「ワイルドカード」と呼ぶ
[3] スーパータイプ バウンド (supertype bound)
super:<? super クラス名>
* 「このクラスのスーパークラスなら何でも」という指定方法 * 以下の参考文献の図が分かりやすいhttp://java.keicode.com/lang/generics-super-bounded.php
補足:PECS原則
PECS; producer -extends consumer -super [1] 引数のデータがプログラム内で使われる場合は extends を使用する [2] 引数にプログラム内のデータがセットされる場合は super を使用する
サンプル
http://blogs.yahoo.co.jp/dk521123/32096812.htmlで作成したサンプルを汎用的に使えるようにする
XmlSerializer.java
import java.beans.XMLDecoder; import java.beans.XMLEncoder; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; public class XmlSerializer { public static void main(String[] args) { List<Person> people = new ArrayList<>(); Person person1 = new Person("Ken", 62); people.add(person1); Person person2 = new Person("Coco", 10); people.add(person2); String fileName = "people.xml"; save(fileName, people); List<Person> newPeople = load(fileName); // 出力 for (Person person : newPeople) { System.out.println(person.getName() + "(" + person.getAge() + ")"); } System.out.println("Done"); } public static <T> void save(String fileName, T objectToSave) { try (XMLEncoder xMLEncoder = new XMLEncoder(new BufferedOutputStream(new FileOutputStream(fileName)));) { xMLEncoder.writeObject(objectToSave); } catch (FileNotFoundException e) { e.printStackTrace(); } } @SuppressWarnings("unchecked") public static <T> T load(String fileName) { try (XMLDecoder xMLDecoder = new XMLDecoder((new BufferedInputStream(new FileInputStream(fileName))));) { Object objectFromXml = xMLDecoder.readObject(); return (T) objectFromXml; } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }
Person.java
* 対象となるオブジェクトimport java.io.Serializable; public class Person implements Serializable { private static final long serialVersionUID = -6612003848170755512L; private String name; private int age; // ★デフォルト・コンストラクタが必要★ public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public int getAge() { return this.age; } public void setAge(int age) { this.age = age; } }
出力
People.xml
<?xml version="1.0" encoding="UTF-8"?> <java version="1.8.0" class="java.beans.XMLDecoder"> <object class="java.util.ArrayList"> <void method="add"> <object class="com.sample.xml.Person"> <void property="age"> <int>62</int> </void> <void property="name"> <string>Ken</string> </void> </object> </void> <void method="add"> <object class="com.sample.xml.Person"> <void property="age"> <int>10</int> </void> <void property="name"> <string>Coco</string> </void> </object> </void> </object> </java>
コンソール画面
Ken(62) Coco(10) Done
補足:Exceptionの発生タイミングについて
* XMLファイルと異なるクラスを読みだした場合、load()内のキャストで例外が発生するのでなく以下の★部分で発生するString fileName = "people.xml"; List<OtherClass> newPeople = XmlSerializer.load(fileName); // 出力 for (Xxx person : newPeople) { //★ここで「ClassCastException」が発生★ System.out.println(person.getName() + "(" + person.getAge() + ")"); * 以下の関連記事でこの問題を修正http://blogs.yahoo.co.jp/dk521123/36358058.html
使用例
その1
* JAXB のユーティリティ クラスをジェネリックで作る (以下の関連記事を参照のこと)http://blogs.yahoo.co.jp/dk521123/34947779.html
その2
* List <=> 配列の相互変換をジェネリックで作る (以下の関連記事を参照のこと)http://blogs.yahoo.co.jp/dk521123/32156111.html
参考文献
ワイルドカード
http://java.keicode.com/lang/generics-wildcard.phpPECS原則
http://javatechnology.net/java/generics-class/http://d.hatena.ne.jp/amachang/20100225/1267073381
http://d.hatena.ne.jp/hageyahhoo/20091012/1255324491
http://www.xmisao.com/2014/02/12/java-pecs-producer-extends-consumer-super.html
http://ameblo.jp/narazumono0321/entry-11459198426.html