Java泛型詳解

2516326-5475e88a458a09e4.png

一,打破砂鍋問到底

泛型存在的意義?
泛型類表悬,泛型接口胜卤,泛型方法如何定義?
如何限定類型變量综膀?
泛型中使用的約束和局限性有哪些澳迫?
泛型類型的繼承規(guī)則是什么?
泛型中的通配符類型是什么剧劝?
如何獲取泛型的參數(shù)類型橄登?
虛擬機(jī)是如何實(shí)現(xiàn)泛型的?
在日常開發(fā)中是如何運(yùn)用泛型的讥此?

Java泛型詳解.png

二拢锹,曉之以理動(dòng)之以碼

1,泛型的定義以及存在意義

泛型萄喳,即“參數(shù)化類型”卒稳。就是將類型由原來的具體的類型參數(shù)化,類似于方法中的變量參數(shù)他巨,此時(shí)類型也定義成參數(shù)形式(可以稱之為類型形參)充坑,然后在使用/調(diào)用時(shí)傳入具體的類型(類型實(shí)參)减江。
例如:GenericClass<T>{}

一些常用的泛型類型變量:
E:元素(Element),多用于java集合框架
K:關(guān)鍵字(Key)
N:數(shù)字(Number)
T:類型(Type)
V:值(Value)

如果要實(shí)現(xiàn)不同類型的加法捻爷,每種類型都需要重載一個(gè)add方法

package com.jay.java.泛型.needGeneric;

/**
 * Author:Jay On 2019/5/9 16:06
 * <p>
 * Description: 為什么使用泛型
 */
public class NeedGeneric1 {

    private static int add(int a, int b) {
        System.out.println(a + "+" + b + "=" + (a + b));
        return a + b;
    }

    private static float add(float a, float b) {
        System.out.println(a + "+" + b + "=" + (a + b));
        return a + b;
    }

    private static double add(double a, double b) {
        System.out.println(a + "+" + b + "=" + (a + b));
        return a + b;
    }

    private static <T extends Number> double add(T a, T b) {
        System.out.println(a + "+" + b + "=" + (a.doubleValue() + b.doubleValue()));
        return a.doubleValue() + b.doubleValue();
    }

    public static void main(String[] args) {
        NeedGeneric1.add(1, 2);
        NeedGeneric1.add(1f, 2f);
        NeedGeneric1.add(1d, 2d);
        NeedGeneric1.add(Integer.valueOf(1), Integer.valueOf(2));
        NeedGeneric1.add(Float.valueOf(1), Float.valueOf(2));
        NeedGeneric1.add(Double.valueOf(1), Double.valueOf(2));
    }
}

取出集合元素時(shí)需要人為的強(qiáng)制類型轉(zhuǎn)化到具體的目標(biāo)類型辈灼,且很容易現(xiàn)“java.lang. ClassCast Exception”異常。

package com.jay.java.泛型.needGeneric;

import java.util.ArrayList;
import java.util.List;

/**
 * Author:Jay On 2019/5/9 16:23
 * <p>
 * Description: 為什么要使用泛型
 */
public class NeedGeneric2 {
    static class C{

    }
    public static void main(String[] args) {
        List list=new ArrayList();
        list.add("A");
        list.add("B");
        list.add(new C());
        list.add(100);
        //1.當(dāng)我們將一個(gè)對(duì)象放入集合中也榄,集合不會(huì)記住此對(duì)象的類型巡莹,當(dāng)再次從集合中取出此對(duì)象時(shí),改對(duì)象的編譯類型變成了Object類型甜紫,但其運(yùn)行時(shí)類型任然為其本身類型榕莺。
        //2.因此,//1處取出集合元素時(shí)需要人為的強(qiáng)制類型轉(zhuǎn)化到具體的目標(biāo)類型棵介,且很容易出現(xiàn)“java.lang.ClassCastException”異常钉鸯。
        for (int i = 0; i < list.size(); i++) {
//            System.out.println(list.get(i));
            String value= (String) list.get(i);
            System.out.println(value);
        }
    }
}

所以使用泛型的意義在于
1,適用于多種數(shù)據(jù)類型執(zhí)行相同的代碼(代碼復(fù)用)
2, 泛型中的類型在使用時(shí)指定,不需要強(qiáng)制類型轉(zhuǎn)換(類型安全邮辽,編譯器會(huì)檢查類型)

2唠雕,泛型類的使用

定義一個(gè)泛型類:public class GenericClass<T>{}

package com.jay.java.泛型.DefineGeneric;

/**
 * Author:Jay On 2019/5/9 16:49
 * <p>
 * Description: 泛型類
 */
public class GenericClass<T> {
    private T data;

    public T getData() {
        return data;
    }

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

    public static void main(String[] args) {
        GenericClass<String> genericClass=new GenericClass<>();
        genericClass.setData("Generic Class");
        System.out.println(genericClass.getData());
    }
}

3,泛型接口的使用

定義一個(gè)泛型接口:public interface GenericIntercace<T>{}

/**
 * Author:Jay On 2019/5/9 16:57
 * <p>
 * Description: 泛型接口
 */
public interface GenericIntercace<T> {
     T getData();
}

實(shí)現(xiàn)泛型接口方式一:public class ImplGenericInterface1<T> implements GenericIntercace<T>

/**
 * Author:Jay On 2019/5/9 16:59
 * <p>
 * Description: 泛型接口實(shí)現(xiàn)類-泛型類實(shí)現(xiàn)方式
 */
public class ImplGenericInterface1<T> implements GenericIntercace<T> {
    private T data;

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

    @Override
    public T getData() {
        return data;
    }

    public static void main(String[] args) {
        ImplGenericInterface1<String> implGenericInterface1 = new ImplGenericInterface1<>();
        implGenericInterface1.setData("Generic Interface1");
        System.out.println(implGenericInterface1.getData());
    }
}

實(shí)現(xiàn)泛型接口方式二:public class ImplGenericInterface2 implements GenericIntercace<String> {}

/**
 * Author:Jay On 2019/5/9 17:01
 * <p>
 * Description: 泛型接口實(shí)現(xiàn)類-指定具體類型實(shí)現(xiàn)方式
 */
public class ImplGenericInterface2 implements GenericIntercace<String> {
    @Override
    public String getData() {
        return "Generic Interface2";
    }

    public static void main(String[] args) {
        ImplGenericInterface2 implGenericInterface2 = new ImplGenericInterface2();
        System.out.println(implGenericInterface2.getData());
    }
}

4吨述,泛型方法的使用

定義一個(gè)泛型方法: private static<T> TgenericAdd(T a, T b) {}

/**
 * Author:Jay On 2019/5/10 10:46
 * <p>
 * Description: 泛型方法
 */
public class GenericMethod1 {
    private static int add(int a, int b) {
        System.out.println(a + "+" + b + "=" + (a + b));
        return a + b;
    }

    private static <T> T genericAdd(T a, T b) {
        System.out.println(a + "+" + b + "="+a+b);
        return a;
    }

    public static void main(String[] args) {
        GenericMethod1.add(1, 2);
        GenericMethod1.<String>genericAdd("a", "b");
    }
}
/**
 * Author:Jay On 2019/5/10 16:22
 * <p>
 * Description: 泛型方法
 */
public class GenericMethod3 {

    static class Animal {
        @Override
        public String toString() {
            return "Animal";
        }
    }

    static class Dog extends Animal {
        @Override
        public String toString() {
            return "Dog";
        }
    }

    static class Fruit {
        @Override
        public String toString() {
            return "Fruit";
        }
    }

    static class GenericClass<T> {

        public void show01(T t) {
            System.out.println(t.toString());
        }

        public <T> void show02(T t) {
            System.out.println(t.toString());
        }

        public <K> void show03(K k) {
            System.out.println(k.toString());
        }
    }

    public static void main(String[] args) {
        Animal animal = new Animal();
        Dog dog = new Dog();
        Fruit fruit = new Fruit();
        GenericClass<Animal> genericClass = new GenericClass<>();
        //泛型類在初始化時(shí)限制了參數(shù)類型
        genericClass.show01(dog);
//        genericClass.show01(fruit);

        //泛型方法的參數(shù)類型在使用時(shí)指定
        genericClass.show02(dog);
        genericClass.show02(fruit);

        genericClass.<Animal>show03(animal);
        genericClass.<Animal>show03(dog);
        genericClass.show03(fruit);
//        genericClass.<Dog>show03(animal);
    }
}

5岩睁,限定泛型類型變量

1,對(duì)類的限定:public class TypeLimitForClass<T extends List & Serializable>{}
2,對(duì)方法的限定:public static<T extends Comparable<T>>T getMin(T a, T b) {}

/**
 * Author:Jay On 2019/5/10 16:38
 * <p>
 * Description: 類型變量的限定-方法
 */
public class TypeLimitForMethod {

    /**
     * 計(jì)算最小值
     * 如果要實(shí)現(xiàn)這樣的功能就需要對(duì)泛型方法的類型做出限定
     */
//    private static <T> T getMin(T a, T b) {
//        return (a.compareTo(b) > 0) ? a : b;
//    }

    /**
     * 限定類型使用extends關(guān)鍵字指定
     * 可以使類,接口揣云,類放在前面接口放在后面用&符號(hào)分割
     * 例如:<T extends ArrayList & Comparable<T> & Serializable>
     */
    public static <T extends Comparable<T>> T getMin(T a, T b) {
        return (a.compareTo(b) < 0) ? a : b;
    }

    public static void main(String[] args) {
        System.out.println(TypeLimitForMethod.getMin(2, 4));
        System.out.println(TypeLimitForMethod.getMin("a", "r"));
    }
}
/**
 * Author:Jay On 2019/5/10 17:02
 * <p>
 * Description: 類型變量的限定-類
 */
public class TypeLimitForClass<T extends List & Serializable> {
    private T data;

    public T getData() {
        return data;
    }

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

    public static void main(String[] args) {
        ArrayList<String> stringArrayList = new ArrayList<>();
        stringArrayList.add("A");
        stringArrayList.add("B");
        ArrayList<Integer> integerArrayList = new ArrayList<>();
        integerArrayList.add(1);
        integerArrayList.add(2);
        integerArrayList.add(3);
        TypeLimitForClass<ArrayList> typeLimitForClass01 = new TypeLimitForClass<>();
        typeLimitForClass01.setData(stringArrayList);
        TypeLimitForClass<ArrayList> typeLimitForClass02 = new TypeLimitForClass<>();
        typeLimitForClass02.setData(integerArrayList);

        System.out.println(getMinListSize(typeLimitForClass01.getData().size(), typeLimitForClass02.getData().size()));

    }

    public static <T extends Comparable<T>> T getMinListSize(T a, T b) {
        return (a.compareTo(b) < 0) ? a : b;
    }

6捕儒,泛型中的約束和局限性

1,不能實(shí)例化泛型類
2,靜態(tài)變量或方法不能引用泛型類型變量,但是靜態(tài)泛型方法是可以的
3,基本類型無法作為泛型類型
4,無法使用instanceof關(guān)鍵字或==判斷泛型類的類型
5,泛型類的原生類型與所傳遞的泛型無關(guān)邓夕,無論傳遞什么類型刘莹,原生類是一樣的
6,泛型數(shù)組可以聲明但無法實(shí)例化
7,泛型類不能繼承Exception或者Throwable
8,不能捕獲泛型類型限定的異常但可以將泛型限定的異常拋出

/**
 * Author:Jay On 2019/5/10 17:41
 * <p>
 * Description: 泛型的約束和局限性
 */
public class GenericRestrict1<T> {
    static class NormalClass {

    }

    private T data;

    /**
     * 不能實(shí)例化泛型類
     * Type parameter 'T' cannot be instantiated directly
     */
    public void setData() {
        //this.data = new T();
    }

    /**
     * 靜態(tài)變量或方法不能引用泛型類型變量
     * 'com.jay.java.泛型.restrict.GenericRestrict1.this' cannot be referenced from a static context
     */
//    private static T result;

//    private static T getResult() {
//        return result;
//    }

    /**
     * 靜態(tài)泛型方法是可以的
     */
    private static <K> K getKey(K k) {
        return k;
    }

    public static void main(String[] args) {
        NormalClass normalClassA = new NormalClass();
        NormalClass normalClassB = new NormalClass();
        /**
         * 基本類型無法作為泛型類型
         */
//        GenericRestrict1<int> genericRestrictInt = new GenericRestrict1<>();
        GenericRestrict1<Integer> genericRestrictInteger = new GenericRestrict1<>();
        GenericRestrict1<String> genericRestrictString = new GenericRestrict1<>();
        /**
         * 無法使用instanceof關(guān)鍵字判斷泛型類的類型
         * Illegal generic type for instanceof
         */
//        if(genericRestrictInteger instanceof GenericRestrict1<Integer>){
//            return;
//        }

        /**
         * 無法使用“==”判斷兩個(gè)泛型類的實(shí)例
         * Operator '==' cannot be applied to this two instance
         */
//        if (genericRestrictInteger == genericRestrictString) {
//            return;
//        }

        /**
         * 泛型類的原生類型與所傳遞的泛型無關(guān),無論傳遞什么類型焚刚,原生類是一樣的
         */
        System.out.println(normalClassA == normalClassB);//false
        System.out.println(genericRestrictInteger == genericRestrictInteger);//
        System.out.println(genericRestrictInteger.getClass() == genericRestrictString.getClass()); //true
        System.out.println(genericRestrictInteger.getClass());//com.jay.java.泛型.restrict.GenericRestrict1
        System.out.println(genericRestrictString.getClass());//com.jay.java.泛型.restrict.GenericRestrict1

        /**
         * 泛型數(shù)組可以聲明但無法實(shí)例化
         * Generic array creation
         */
        GenericRestrict1<String>[] genericRestrict1s;
//        genericRestrict1s = new GenericRestrict1<String>[10];
        genericRestrict1s = new GenericRestrict1[10];
        genericRestrict1s[0]=genericRestrictString;
    }

}
/**
 * Author:Jay On 2019/5/10 18:45
 * <p>
 * Description: 泛型和異常
 */
public class GenericRestrict2 {

    private class MyException extends Exception {
    }

    /**
     * 泛型類不能繼承Exception或者Throwable
     * Generic class may not extend 'java.lang.Throwable'
     */
//    private class MyGenericException<T> extends Exception {
//    }
//
//    private class MyGenericThrowable<T> extends Throwable {
//    }

    /**
     * 不能捕獲泛型類型限定的異常
     * Cannot catch type parameters
     */
    public <T extends Exception> void getException(T t) {
//        try {
//
//        } catch (T e) {
//
//        }
    }

    /**
     *可以將泛型限定的異常拋出
     */
    public <T extends Throwable> void getException(T t) throws T {
        try {

        } catch (Exception e) {
            throw t;
        }
    }
}

7点弯,泛型類型繼承規(guī)則

1,對(duì)于泛型參數(shù)是繼承關(guān)系的泛型類之間是沒有繼承關(guān)系的
2,泛型類可以繼承其它泛型類,例如: public class ArrayList<E> extends AbstractList<E>
3,泛型類的繼承關(guān)系在使用中同樣會(huì)受到泛型類型的影響

/**
 * Author:Jay On 2019/5/10 19:13
 * <p>
 * Description: 泛型繼承規(guī)則測(cè)試類
 */
public class GenericInherit<T> {
    private T data1;
    private T data2;

    public T getData1() {
        return data1;
    }

    public void setData1(T data1) {
        this.data1 = data1;
    }

    public T getData2() {
        return data2;
    }

    public void setData2(T data2) {
        this.data2 = data2;
    }

    public static <V> void setData2(GenericInherit<Father> data2) {

    }

    public static void main(String[] args) {
//        Son 繼承自 Father
        Father father = new Father();
        Son son = new Son();
        GenericInherit<Father> fatherGenericInherit = new GenericInherit<>();
        GenericInherit<Son> sonGenericInherit = new GenericInherit<>();
        SubGenericInherit<Father> fatherSubGenericInherit = new SubGenericInherit<>();
        SubGenericInherit<Son> sonSubGenericInherit = new SubGenericInherit<>();

        /**
         * 對(duì)于傳遞的泛型類型是繼承關(guān)系的泛型類之間是沒有繼承關(guān)系的
         * GenericInherit<Father> 與GenericInherit<Son> 沒有繼承關(guān)系
         * Incompatible types.
         */
        father = new Son();
//        fatherGenericInherit=new GenericInherit<Son>();

        /**
         * 泛型類可以繼承其它泛型類矿咕,例如: public class ArrayList<E> extends AbstractList<E>
         */
        fatherGenericInherit=new SubGenericInherit<Father>();

        /**
         *泛型類的繼承關(guān)系在使用中同樣會(huì)受到泛型類型的影響
         */
        setData2(fatherGenericInherit);
//        setData2(sonGenericInherit);
        setData2(fatherSubGenericInherit);
//        setData2(sonSubGenericInherit);

    }

    private static class SubGenericInherit<T> extends GenericInherit<T> {

    }

8抢肛,通配符類型

1,<? extends Parent> 指定了泛型類型的上屆
2,<? super Child> 指定了泛型類型的下屆
3, <?> 指定了沒有限制的泛型類型

通配符測(cè)試類結(jié)構(gòu).png
/**
 * Author:Jay On 2019/5/10 19:51
 * <p>
 * Description: 泛型通配符測(cè)試類
 */
public class GenericByWildcard {
    private static void print(GenericClass<Fruit> fruitGenericClass) {
        System.out.println(fruitGenericClass.getData().getColor());
    }

    private static void use() {
        GenericClass<Fruit> fruitGenericClass = new GenericClass<>();
        print(fruitGenericClass);
        GenericClass<Orange> orangeGenericClass = new GenericClass<>();
        //類型不匹配,可以使用<? extends Parent> 來解決
//        print(orangeGenericClass);
    }

    /**
     * <? extends Parent> 指定了泛型類型的上屆
     */
    private static void printExtends(GenericClass<? extends Fruit> genericClass) {
        System.out.println(genericClass.getData().getColor());
    }

    public static void useExtend() {
        GenericClass<Fruit> fruitGenericClass = new GenericClass<>();
        printExtends(fruitGenericClass);
        GenericClass<Orange> orangeGenericClass = new GenericClass<>();
        printExtends(orangeGenericClass);

        GenericClass<Food> foodGenericClass = new GenericClass<>();
        //Food是Fruit的父類,超過了泛型上屆范圍碳柱,類型不匹配
//        printExtends(foodGenericClass);

        //表示GenericClass的類型參數(shù)的上屆是Fruit
        GenericClass<? extends Fruit> extendFruitGenericClass = new GenericClass<>();
        Apple apple = new Apple();
        Fruit fruit = new Fruit();
        /*
         * 道理很簡(jiǎn)單捡絮,? extends X  表示類型的上界莲镣,類型參數(shù)是X的子類福稳,那么可以肯定的說,
         * get方法返回的一定是個(gè)X(不管是X或者X的子類)編譯器是可以確定知道的剥悟。
         * 但是set方法只知道傳入的是個(gè)X灵寺,至于具體是X的那個(gè)子類曼库,不知道。
         * 總結(jié):主要用于安全地訪問數(shù)據(jù)略板,可以訪問X及其子類型毁枯,并且不能寫入非null的數(shù)據(jù)。
         */
//        extendFruitGenericClass.setData(apple);
//        extendFruitGenericClass.setData(fruit);

        fruit = extendFruitGenericClass.getData();

    }

    /**
     * <? super Child> 指定了泛型類型的下屆
     */
    public static void printSuper(GenericClass<? super Apple> genericClass) {
        System.out.println(genericClass.getData());
    }

    public static void useSuper() {
        GenericClass<Food> foodGenericClass = new GenericClass<>();
        printSuper(foodGenericClass);

        GenericClass<Fruit> fruitGenericClass = new GenericClass<>();
        printSuper(fruitGenericClass);

        GenericClass<Apple> appleGenericClass = new GenericClass<>();
        printSuper(appleGenericClass);

        GenericClass<HongFuShiApple> hongFuShiAppleGenericClass = new GenericClass<>();
        // HongFuShiApple 是Apple的子類叮称,達(dá)不到泛型下屆种玛,類型不匹配
//        printSuper(hongFuShiAppleGenericClass);

        GenericClass<Orange> orangeGenericClass = new GenericClass<>();
        // Orange和Apple是兄弟關(guān)系,沒有繼承關(guān)系瓤檐,類型不匹配
//        printSuper(orangeGenericClass);

        //表示GenericClass的類型參數(shù)的下界是Apple
        GenericClass<? super Apple> supperAppleGenericClass = new GenericClass<>();
        supperAppleGenericClass.setData(new Apple());
        supperAppleGenericClass.setData(new HongFuShiApple());
        /*
         * 赂韵? super  X  表示類型的下界,類型參數(shù)是X的超類(包括X本身)挠蛉,
         * 那么可以肯定的說祭示,get方法返回的一定是個(gè)X的超類,那么到底是哪個(gè)超類谴古?不知道质涛,
         * 但是可以肯定的說,Object一定是它的超類掰担,所以get方法返回Object汇陆。
         * 編譯器是可以確定知道的。對(duì)于set方法來說带饱,編譯器不知道它需要的確切類型毡代,但是X和X的子類可以安全的轉(zhuǎn)型為X。
         * 總結(jié):主要用于安全地寫入數(shù)據(jù)勺疼,可以寫入X及其子類型教寂。
         */
//        supperAppleGenericClass.setData(new Fruit());

        //get方法只會(huì)返回一個(gè)Object類型的值。
        Object data = supperAppleGenericClass.getData();
    }

    /**
     * <?> 指定了沒有限定的通配符
     */
    public static void printNonLimit(GenericClass<?> genericClass) {
        System.out.println(genericClass.getData());
    }

    public static void useNonLimit() {
        GenericClass<Food> foodGenericClass = new GenericClass<>();
        printNonLimit(foodGenericClass);
        GenericClass<Fruit> fruitGenericClass = new GenericClass<>();
        printNonLimit(fruitGenericClass);
        GenericClass<Apple> appleGenericClass = new GenericClass<>();
        printNonLimit(appleGenericClass);

        GenericClass<?> genericClass = new GenericClass<>();
        //setData 方法不能被調(diào)用恢口, 甚至不能用 Object 調(diào)用孝宗;
//        genericClass.setData(foodGenericClass);
//        genericClass.setData(new Object());
        //返回值只能賦給 Object
        Object object = genericClass.getData();

    }

}

9,獲取泛型的參數(shù)類型

Type是什么
這里的Type指java.lang.reflect.Type, 是Java中所有類型的公共高級(jí)接口, 代表了Java中的所有類型. Type體系中類型的包括:數(shù)組類型(GenericArrayType)耕肩、參數(shù)化類型(ParameterizedType)、類型變量(TypeVariable)问潭、通配符類型(WildcardType)猿诸、原始類型(Class)、基本類型(Class), 以上這些類型都實(shí)現(xiàn)Type接口.

參數(shù)化類型,就是我們平常所用到的泛型List狡忙、Map梳虽;
數(shù)組類型,并不是我們工作中所使用的數(shù)組String[] 、byte[]灾茁,而是帶有泛型的數(shù)組窜觉,即T[] 谷炸;
通配符類型, 指的是<?>, <? extends T>等等
原始類型, 不僅僅包含我們平常所指的類,還包括枚舉禀挫、數(shù)組旬陡、注解等;
基本類型, 也就是我們所說的java的基本類型语婴,即int,float,double等

public interface ParameterizedType extends Type {
    // 返回確切的泛型參數(shù), 如Map<String, Integer>返回[String, Integer]
    Type[] getActualTypeArguments();
    
    //返回當(dāng)前class或interface聲明的類型, 如List<?>返回List
    Type getRawType();
    
    //返回所屬類型. 如,當(dāng)前類型為O<T>.I<S>, 則返回O<T>. 頂級(jí)類型將返回null 
    Type getOwnerType();
}
/**
 * Author:Jay On 2019/5/11 22:41
 * <p>
 * Description: 獲取泛型類型測(cè)試類
 */
public class GenericType<T> {
    private T data;

    public T getData() {
        return data;
    }

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

    public static void main(String[] args) {
        GenericType<String> genericType = new GenericType<String>() {};
        Type superclass = genericType.getClass().getGenericSuperclass();
        //getActualTypeArguments 返回確切的泛型參數(shù), 如Map<String, Integer>返回[String, Integer]
        Type type = ((ParameterizedType) superclass).getActualTypeArguments()[0]; 
        System.out.println(type);//class java.lang.String
    }
}

10描孟,虛擬機(jī)是如何實(shí)現(xiàn)泛型的

Java泛型是Java1.5之后才引入的,為了向下兼容砰左。Java采用了C++完全不同的實(shí)現(xiàn)思想匿醒。Java中的泛型更多的看起來像是編譯期用的
Java中泛型在運(yùn)行期是不可見的,會(huì)被擦除為它的上級(jí)類型缠导。如果是沒有限定的泛型參數(shù)類型廉羔,就會(huì)被替換為Object.

GenericClass<String> stringGenericClass=new GenericClass<>();
GenericClass<Integer> integerGenericClass=new GenericClass<>();

C++中GenericClass<String>和GenericClass<Integer>是兩個(gè)不同的類型
Java進(jìn)行了類型擦除之后統(tǒng)一改為GenericClass<Object>

/**
 * Author:Jay On 2019/5/11 16:11
 * <p>
 * Description:泛型原理測(cè)試類
 */
public class GenericTheory {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("Key", "Value");
        System.out.println(map.get("Key"));
        GenericClass<String, String> genericClass = new GenericClass<>();
        genericClass.put("Key", "Value");
        System.out.println(genericClass.get("Key"));
    }

    public static class GenericClass<K, V> {
        private K key;
        private V value;

        public void put(K key, V value) {
            this.key = key;
            this.value = value;
        }

        public V get(V key) {
            return value;
        }
    }

    /**
     * 類型擦除后GenericClass2<Object>
     * @param <T>
     */
    private class GenericClass2<T> {

    }

    /**
     * 類型擦除后GenericClass3<ArrayList>
     * 當(dāng)使用到Serializable時(shí)會(huì)將相應(yīng)代碼強(qiáng)制轉(zhuǎn)換為Serializable
     * @param <T>
     */
    private class GenericClass3<T extends ArrayList & Serializable> {

    }
}

對(duì)應(yīng)的字節(jié)碼文件

 public static void main(String[] args) {
        Map<String, String> map = new HashMap();
        map.put("Key", "Value");
        System.out.println((String)map.get("Key"));
        GenericTheory.GenericClass<String, String> genericClass = new GenericTheory.GenericClass();
        genericClass.put("Key", "Value");
        System.out.println((String)genericClass.get("Key"));
    }

三,學(xué)以致用

1僻造,泛型解析JSON數(shù)據(jù)封裝

api返回的json數(shù)據(jù)

{
    "code":200,
    "msg":"成功",
    "data":{
        "name":"Jay",
        "email":"10086"
    }
}

BaseResponse .java

/**
 * Author:Jay On 2019/5/11 20:48
 * <p>
 * Description: 接口數(shù)據(jù)接收基類
 */
public class BaseResponse {

    private int code;
    private String msg;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

UserResponse.java

/**
 * Author:Jay On 2019/5/11 20:49
 * <p>
 * Description: 用戶信息接口實(shí)體類
 */
public class UserResponse<T> extends BaseResponse {
    private T data;

    public T getData() {
        return data;
    }

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

2憋他,泛型+反射實(shí)現(xiàn)巧復(fù)用工具類

/**
 * Author:Jay On 2019/5/11 21:05
 * <p>
 * Description: 泛型相關(guān)的工具類
 */
public class GenericUtils {

    public static class Movie {
        private String name;
        private Date time;

        public String getName() {
            return name;
        }

        public Date getTime() {
            return time;
        }

        public Movie(String name, Date time) {
            this.name = name;
            this.time = time;
        }

        @Override
        public String toString() {
            return "Movie{" + "name='" + name + '\'' + ", time=" + time + '}';
        }
    }

    public static void main(String[] args) {
        List<Movie> movieList = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            movieList.add(new Movie("movie" + i, new Date()));
        }
        System.out.println("排序前:" + movieList.toString());

        GenericUtils.sortAnyList(movieList, "name", true);
        System.out.println("按name正序排:" + movieList.toString());

        GenericUtils.sortAnyList(movieList, "name", false);
        System.out.println("按name逆序排:" + movieList.toString());
    }

    /**
     * 對(duì)任意集合的排序方法
     * @param targetList 要排序的實(shí)體類List集合
     * @param sortField  排序字段
     * @param sortMode   true正序,false逆序
     */
    public static <T> void sortAnyList(List<T> targetList, final String sortField, final boolean sortMode) {
        if (targetList == null || targetList.size() < 2 || sortField == null || sortField.length() == 0) {
            return;
        }
        Collections.sort(targetList, new Comparator<Object>() {
            @Override
            public int compare(Object obj1, Object obj2) {
                int retVal = 0;
                try {
                    // 獲取getXxx()方法名稱
                    String methodStr = "get" + sortField.substring(0, 1).toUpperCase() + sortField.substring(1);
                    Method method1 = ((T) obj1).getClass().getMethod(methodStr, null);
                    Method method2 = ((T) obj2).getClass().getMethod(methodStr, null);
                    if (sortMode) {
                        retVal = method1.invoke(((T) obj1), null).toString().compareTo(method2.invoke(((T) obj2), null).toString());
                    } else {
                        retVal = method2.invoke(((T) obj2), null).toString().compareTo(method1.invoke(((T) obj1), null).toString());
                    }
                } catch (Exception e) {
                    System.out.println("List<" + ((T) obj1).getClass().getName() + ">排序異常嫡意!");
                    e.printStackTrace();
                }
                return retVal;
            }
        });
    }
}

3举瑰,Gson庫中的泛型的使用-TypeToken

/**
 * Author:Jay On 2019/5/11 22:11
 * <p>
 * Description: Gson庫中的泛型使用
 */
public class GsonGeneric {
    public static class Person {
        private String name;
        private int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

    public static void main(String[] args) {
        Gson gson = new Gson();
        List<Person> personList = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            personList.add(new Person("name" + i, 18 + i));
        }
        // Serialization
        String json = gson.toJson(personList);
        System.out.println(json);
        // Deserialization
        Type personType = new TypeToken<List<Person>>() {}.getType();
        List<Person> personList2 = gson.fromJson(json, personType);
        System.out.println(personList2);
    }
}

測(cè)試代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蔬螟,隨后出現(xiàn)的幾起案子此迅,更是在濱河造成了極大的恐慌,老刑警劉巖旧巾,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件耸序,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡鲁猩,警方通過查閱死者的電腦和手機(jī)坎怪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來廓握,“玉大人搅窿,你說我怎么就攤上這事∠度” “怎么了男应?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)娱仔。 經(jīng)常有香客問我沐飘,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任耐朴,我火速辦了婚禮借卧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘筛峭。我一直安慰自己铐刘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布蜒滩。 她就那樣靜靜地躺著滨达,像睡著了一般。 火紅的嫁衣襯著肌膚如雪俯艰。 梳的紋絲不亂的頭發(fā)上捡遍,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音竹握,去河邊找鬼画株。 笑死,一個(gè)胖子當(dāng)著我的面吹牛啦辐,可吹牛的內(nèi)容都是我干的谓传。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼芹关,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼续挟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起侥衬,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤诗祸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后轴总,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體直颅,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年怀樟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了功偿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡往堡,死狀恐怖械荷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情虑灰,我是刑警寧澤养葵,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站瘩缆,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏佃蚜。R本人自食惡果不足惜庸娱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一着绊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧熟尉,春花似錦归露、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至往果,卻和暖如春疆液,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背陕贮。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國打工堕油, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人肮之。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓掉缺,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親戈擒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子眶明,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 泛型 泛型由來 泛型字面意思不知道是什么類型,但又好像什么類型都是筐高∷汛眩看前面用到的集合都有泛型的影子。 以Array...
    向日花開閱讀 2,194評(píng)論 2 6
  • 最近項(xiàng)目組在進(jìn)行泛型代碼編寫時(shí)遇到很多困難凯傲,討論下來發(fā)現(xiàn)大家對(duì)這個(gè)概念都是一知片解犬辰,然而在我們的項(xiàng)目開發(fā)過程中,又...
    Caprin閱讀 4,926評(píng)論 2 47
  • 由于博客的特殊顯示原因冰单,尖括號(hào)用()代替 泛型概述 Java泛型(generics)是JDK 5中引入的一個(gè)新特性...
    馮匿閱讀 677評(píng)論 0 0
  • 2.6 Java泛型詳解 Java泛型是JDK5中引入的一個(gè)新特性幌缝,允許在定義類和接口的時(shí)候使用類型參數(shù)(type...
    jianhuih閱讀 686評(píng)論 0 3
  • 為什么要使用泛型? 一般的類和方法诫欠,只能使用具體的類型涵卵;要么是基本類型,要么是自定義類荒叼。如果我有這種需求:可以應(yīng)用...
    糖醋豆腐腦閱讀 328評(píng)論 0 0