' P '

whatever I will forget

Java Generics

Generics (総称型) です。

Genericsとは?

薄い理解としては、型タイプを指定し、想定していないタイプがメソッドやクラスに渡された際にコンパイル時にエラーにしてくれるという感じ

Genericsが活きる時

例えば、ArrayListの下記の場合、どんあタイプも受け入られるような感じになっています。
intを期待しているのにいきなりStringがaddされたような場合、実行時までエラーに気づきません。

package com.company;

import java.util.ArrayList;

public class Main {

    public static void main(String[] args) {
        ArrayList list = new ArrayList();

        list.add(1);
        list.add(1);
        list.add(1);
        list.add("aaaa");
        list.add(1);
        printArray(list);
    }

    public static void printArray(ArrayList data) {
        for(Object i : data) {
            System.out.println("data [" + (Integer)i + "]");
        }
    }
}

実行すると下記のような、StringをIntegerにキャストできませんってようなエラーがでます

data [1]
data [1]
data [1]
Exception in thread "main" java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer (java.lang.String and java.lang.Integer are in module java.base of loader 'bootstrap')
    at com.company.Main.printArray(Main.java:20)
    at com.company.Main.main(Main.java:15)

まあここはいままで知らぬ間にやってきていたArrayListのタイプを<>で指定することにより、上記のような問題を発生させないようにする。
ArrayList<Integer> list = new ArrayList<>();

クラスの場合

例えば、abstract classが存在し、それぞれのsub classごとに型を指定しないといけないような場合があったりする。
結構意味のない例ですが、Stringのデータだけいれるリストとintだけいれるリストがあるような場合
<T>を例にしていますが、実はなんでもいいらしいです

import java.util.ArrayList;

public class Main {

    public static void main(String[] args) {
        IntData intData = new IntData("3");
        StrData strData = new StrData("Test");

//        ManageData dataList = new ManageData();
//インスタンスをつくる際にクラス型を指定する
        ManageData<IntData> dataList = new ManageData();

        dataList.addData(intData);
// StrDataを引数に指定するとCompile Errorになる
//        dataList.addData(strData);
        dataList.printData();
    }
}
public abstract class Test {
    private String data;

    public Test(String data) {
        this.data = data;
    }

    public String getData() {
        return data;
    }
}
public class IntData extends Test {
    public IntData(String data) {
        super(data);
    }
}
public class StrData extends Test {
    public StrData(String data) {
        super(data);
    }
}
package com.company;

import java.util.ArrayList;

//Testクラスのメソッドをキャスト無しで呼び出すため、<T extends Class名>とする
//    public class ManageData {
public class ManageData<T extends Test> {

//リストも<T>型に変更する
//    ArrayList<Test> list = new ArrayList<>();
    ArrayList<T> list = new ArrayList<>();

//引数をT型に指定する
//    public void addData(Test data) {
    public void addData(T data) {
        this.list.add(data);
        //Test型にキャストしなくても、getData()が呼び出せる
        System.out.println("data added: " + data.getData());
    }

    public void printData() {
        for(int i=0; i<this.list.size(); i++) {
           //Test型にキャストしなくても、getData()が呼び出せる
            System.out.println("data: " + list.get(i).getData());
        }
    }
}