1. 程式人生 > >java泛型的一些常見用法

java泛型的一些常見用法

本文主要參考下面幾篇文章:

http://blog.csdn.net/seu_calvin/article/details/52230032

http://blog.csdn.net/orzlzro/article/details/7017435

http://sharewind.iteye.com/blog/1622164

https://www.zhihu.com/question/20400700

1、 泛型類(介面)的寫法以及繼承

// 類似java.util.function.Function
public interface GenericInterface<T, R> {
    public R apply(T t);
}

// 類似java.util.stream.IntStream
public interface InheritGeneric0 extends GenericInterface<String, Integer> {
}

// 類似java.util.function.UnaryOperator
public interface InheritGeneric1<T> extends GenericInterface<T, T> {
}

// 類似java.util.HashMap
public interface InheritGeneric2<T, R> extends GenericInterface<T, R> {

}

// JDK庫尚未找到類似的
public interface InheritGeneric3<V, T, R> extends GenericInterface<T, R> {
    public V apply2(T t, R r);
}

2、泛型方法的寫法
public class Retryer<T> {
    private T value;

    private int id = 0;

    public Retryer() {

    }

    public Retryer(int id) {
        this.id = id;
    }

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

// 泛型的宣告:方法的修飾符(public,static,final,abstract等)之後, 返回值(void,int等)之前
public class SpecificClass {

    // 入參泛型,返回值非泛型
    public <L, R> int sum(L[] left, R[] right) {
        return left.length + right.length;
    }

    // 入參非泛型,返回值泛型
    public static <T> Retryer<T> build() {
        return new Retryer<T>();
    }

    // 入參泛型,返回值泛型
    public <L, R, V> Retryer<V> buildLength(L[] left, R[] right) {
        return new Retryer<V>(left.length + right.length);
    }

    // 限制泛型: 只能是某個類的子類或者只能是實現了某些介面的類
    // <T extends Comparable>
    // <T extends Number&Serializable>
    // <T extends Comparable&Serializable>
    public <L extends Number, R extends Number> double add(L left, R right) {
        return left.doubleValue() + right.doubleValue();
    }

}


3、泛型的一些基本特性:不能例項化物件和陣列

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class GenericBasicFeature {
    public static void main(String[] args) {
        test1();

        String[] stringArray = (String[]) Array.newInstance(String.class, 5);
        System.out.println("stringArray.length=" + stringArray.length);

        String[] stringArray2 = GenericBasicFeature.test2(5, String.class);
        System.out.println("stringArray2.length=" + stringArray2.length);
    }

    // 泛型只在編譯期有效
    // http://blog.csdn.net/seu_calvin/article/details/52230032
    public static void test1() {
        List<String> stringList = new ArrayList<String>();
        stringList.add("aaa");

        // 編譯報錯
        // stringList.add(new Object());

        // 執行時通過反射新增元素
        try {
            Class clazz = stringList.getClass();
            Method method = clazz.getMethod("add", Object.class);
            method.invoke(stringList, 100);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // [aaa, 100]
        System.out.println(stringList);
    }

    // java不支援建立泛型陣列
    // http://blog.csdn.net/orzlzro/article/details/7017435
    public static <T> T[] test2(int length, Class<T> newType) {
        // T t = new T(); 編譯錯誤
        // T[] wrong = new T[length]; 編譯錯誤
        // T[] newArray = (T[]) new Object[length]; 執行時ClassCastException

        // 參考Arrays.copyOf
        T[] newArray = (T[]) Array.newInstance(newType, length);
        return newArray;
    }

}

4、泛型的super和extend的PECS原則

// PECS(Producer Extends Consumer Super)
public class Demo {
    static class Food {
    }

    static class Fruit extends Food {
    }

    static class Apple extends Fruit {
    }

    public void testExtend() {
        List<? extends Food> flist = new ArrayList<Food>();
        flist.add(new Apple());  //compile error
        flist.add(new Fruit()); //compile error
        flist.add(new Object()); //compile error

        Food fruit = flist.get(0); //ok
    }

    public void testSuper() {
        List<? super Food> flist = new ArrayList<Food>();
        flist.add(new Food()); //ok
        flist.add(new Fruit()); //ok
        flist.add(new Apple()); //ok

        Food f = flist.get(0);// compile error
    }
}
5、一種使用例子
public class ExtendsContainer<T> {

    private T data;

    public ExtendsContainer(T data) {
        this.data = data;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

public class Demo {
    static class Food {
    }

    static class Fruit extends Food {
    }

    static class Apple extends Fruit {
    }

    public static void main(String[] args) {
        ExtendsContainer<Food> food = new ExtendsContainer<Food>(new Food());
        ExtendsContainer<Fruit> fruit = new ExtendsContainer<Fruit>(new Fruit());
        ExtendsContainer<Apple> apple = new ExtendsContainer<Apple>(new Apple());
        ExtendsContainer<String> string = new ExtendsContainer<String>("abc");

        getDataNoLimit(food);
        getDataNoLimit(fruit);
        getDataNoLimit(apple);
        getDataNoLimit(string);

        getDataOnlyFood(food);
        getDataOnlyFood(fruit);
        getDataOnlyFood(apple);
        getDataOnlyFood(string);

        getDataAnyFood(food);
        getDataAnyFood(fruit);
        getDataAnyFood(apple);
        getDataAnyFood(string);
    }

    public static void getDataNoLimit(ExtendsContainer<?> container) {
        System.out.println("data:" + container.getData());
    }

    public static void getDataOnlyFood(ExtendsContainer<Food> container) {
        System.out.println("data:" + container.getData());
    }

    public static void getDataAnyFood(ExtendsContainer<? extends Food> data) {
        System.out.println("data :" + data.getData());
    }

}