【Java】ジェネリック(Generics) ~<T>型 / クラスやメソッドを汎用的に使えるようにする~

  ジェネリックGenerics)について

  利点

 * キャストが省略できる
 * 誤った型を指定した場合、ビルドエラーになる

 

  構文

  [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 を使用する

 

  コンストラクタの型推論 From Java 7

Map<String, String> map = new HashMap<>();
と省略可能。

 

  サンプル

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

 

 

  関連記事

  オブジェクトのXMLへの読み出し・書き出し

http://blogs.yahoo.co.jp/dk521123/32096812.html

  JAXB のユーティリティ クラスをジェネリックで作る

http://blogs.yahoo.co.jp/dk521123/34947779.html

  【Java】インターフェース・interface

http://blogs.yahoo.co.jp/dk521123/33817801.html

  【C#ジェネリック ~<T>型 / クラスやメソッドを汎用的に使えるようにする~

http://blogs.yahoo.co.jp/dk521123/22167448.html