1. 程式人生 > 實用技巧 >Benelux Algorithm Programming Contest 2016 Preliminary I. Rock Band

Benelux Algorithm Programming Contest 2016 Preliminary I. Rock Band

------------恢復內容開始------------

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

泛型,即“引數化型別”。就是將型別由原來的具體的型別引數化,類似於方法中的變數引數,此時型別也定義成引數形式(可以稱之為型別形參),然後在使用/呼叫時傳入具體的型別(型別實參)。
例如:GenericClass<T>{}

一些常用的泛型型別變數:
E:元素(Element),多用於java集合框架
K:關鍵字(Key)
N:數字(Number)
T:型別(Type)
V:值(Value)

不適用泛型時,如果要實現不同型別的加法,每種型別都需要過載一個add方法,取出集合元素時需要人為的強制型別轉化到具體的目標型別,且很容易現“java.lang. ClassCast Exception”異常

所以使用泛型的意義在於
1,適用於多種資料型別執行相同的程式碼(程式碼複用)
2, 泛型中的型別在使用時指定,不需要強制型別轉換(型別安全,編譯器會檢查型別)

2,泛型類的使用

定義一個泛型類:public classGenericClass<T>{}

public class GenericTest<T> {
    
    private T data;
    public T getData(){
        return data;
    }
}

3,泛型介面的使用

定義一個泛型介面:public interfaceGenericIntercace<T>

{}

public interface GenericInterface<T> {

    T getDate();

}

泛型介面可以實現泛型,也可以實現具體的泛型類。

實現泛型介面方式一:public classImplGenericInterface1<T>implementsGenericIntercace<T>

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()); } }

實現泛型介面方式二:public class ImplGenericInterface2 implementsGenericIntercace<String>{}

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,泛型方法的使用

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

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");
    }
}
    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<>();
        //泛型類在初始化時限制了引數型別
        genericClass.show01(dog);
//        genericClass.show01(fruit);

        //泛型方法的引數型別在使用時指定
        genericClass.show02(dog);
        genericClass.show02(fruit);

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

泛型方法可以在非泛型類中定義,也可以在泛型類中使用與類不同的佔位符來定義。

5,限定泛型型別變數

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

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,不能例項化泛型類
2,靜態變數或方法不能引用泛型型別變數,但是靜態泛型方法是可以的
3,基本型別無法作為泛型型別
4,無法使用instanceof關鍵字或==判斷泛型類的型別
5,泛型類的原生型別與所傳遞的泛型無關,無論傳遞什麼型別,原生類是一樣的
6,泛型陣列可以宣告但無法例項化
7,泛型類不能繼承Exception或者Throwable
8,不能捕獲泛型型別限定的異常但可以將泛型限定的異常丟擲

public class GenericRestrict1<T> {
    static class NormalClass {

    }

    private T data;

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

    /**
     * 靜態變數或方法不能引用泛型型別變數
     * 'com.jay.java.泛型.restrict.GenericRestrict1.this' cannot be referenced from a static context
     */
//    private static T result;

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

    /**
     * 靜態泛型方法是可以的
     */
    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關鍵字判斷泛型類的型別
         * Illegal generic type for instanceof
         */
//        if(genericRestrictInteger instanceof GenericRestrict1<Integer>){
//            return;
//        }

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

        /**
         * 泛型類的原生型別與所傳遞的泛型無關,無論傳遞什麼型別,原生類是一樣的
         */
        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

        /**
         * 泛型陣列可以宣告但無法例項化
         * Generic array creation
         */
        GenericRestrict1<String>[] genericRestrict1s;
//        genericRestrict1s = new GenericRestrict1<String>[10];
        genericRestrict1s = new GenericRestrict1[10];
        genericRestrict1s[0]=genericRestrictString;
    }

}

泛型與異常:

 */
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,泛型型別繼承規則

1,對於泛型引數是繼承關係的泛型類之間是沒有繼承關係的
2,泛型類可以繼承其它泛型類,例如: public class ArrayList<E> extends AbstractList<E>
3,泛型類的繼承關係在使用中同樣會受到泛型型別的影響

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<>();

        /**
         * 對於傳遞的泛型型別是繼承關係的泛型類之間是沒有繼承關係的
         * GenericInherit<Father> 與GenericInherit<Son> 沒有繼承關係
         * Incompatible types.
         */
        father = new Son();
//        fatherGenericInherit=new GenericInherit<Son>();

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

        /**
         *泛型類的繼承關係在使用中同樣會受到泛型型別的影響
         */
        setData2(fatherGenericInherit);
//        setData2(sonGenericInherit);
        setData2(fatherSubGenericInherit);
//        setData2(sonSubGenericInherit);

    }

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

    }

8,萬用字元型別

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

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的型別引數的上屆是Fruit
        GenericClass<? extends Fruit> extendFruitGenericClass = new GenericClass<>();
        Apple apple = new Apple();
        Fruit fruit = new Fruit();
        /*
         * 道理很簡單,? extends X  表示型別的上界,型別引數是X的子類,那麼可以肯定的說,
         * get方法返回的一定是個X(不管是X或者X的子類)編譯器是可以確定知道的。
         * 但是set方法只知道傳入的是個X,至於具體是X的那個子類,不知道。
         * 總結:主要用於安全地訪問資料,可以訪問X及其子型別,並且不能寫入非null的資料。
         */
//        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的子類,達不到泛型下屆,型別不匹配
//        printSuper(hongFuShiAppleGenericClass);

        GenericClass<Orange> orangeGenericClass = new GenericClass<>();
        // Orange和Apple是兄弟關係,沒有繼承關係,型別不匹配
//        printSuper(orangeGenericClass);

        //表示GenericClass的型別引數的下界是Apple
        GenericClass<? super Apple> supperAppleGenericClass = new GenericClass<>();
        supperAppleGenericClass.setData(new Apple());
        supperAppleGenericClass.setData(new HongFuShiApple());
        /*
         * ? super  X  表示型別的下界,型別引數是X的超類(包括X本身),
         * 那麼可以肯定的說,get方法返回的一定是個X的超類,那麼到底是哪個超類?不知道,
         * 但是可以肯定的說,Object一定是它的超類,所以get方法返回Object。
         * 編譯器是可以確定知道的。對於set方法來說,編譯器不知道它需要的確切型別,但是X和X的子類可以安全的轉型為X。
         * 總結:主要用於安全地寫入資料,可以寫入X及其子型別。
         */
//        supperAppleGenericClass.setData(new Fruit());

        //get方法只會返回一個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 方法不能被呼叫, 甚至不能用 Object 呼叫;
//        genericClass.setData(foodGenericClass);
//        genericClass.setData(new Object());
        //返回值只能賦給 Object
        Object object = genericClass.getData();

    }

}

萬用字元型別間有繼承關係

9,獲取泛型的引數型別

Type是什麼
這裡的Type指java.lang.reflect.Type, 是Java中所有型別的公共高階介面, 代表了Java中的所有型別. Type體系中型別的包括:陣列型別(GenericArrayType)、引數化型別(ParameterizedType)、型別變數(TypeVariable)、萬用字元型別(WildcardType)、原始型別(Class)、基本型別(Class), 以上這些型別都實現Type介面.

引數化型別,就是我們平常所用到的泛型List、Map;
陣列型別,並不是我們工作中所使用的陣列String[] 、byte[],而是帶有泛型的陣列,即T[] ;
萬用字元型別, 指的是<?>, <? extends T>等等
原始型別, 不僅僅包含我們平常所指的類,還包括列舉、陣列、註解等;
基本型別, 也就是我們所說的java的基本型別,即int,float,double等

public interface ParameterizedType extends Type {
    // 返回確切的泛型引數, 如Map<String, Integer>返回[String, Integer]
    Type[] getActualTypeArguments();
    
    //返回當前class或interface宣告的型別, 如List<?>返回List
    Type getRawType();
    
    //返回所屬型別. 如,當前型別為O<T>.I<S>, 則返回O<T>. 頂級型別將返回null 
    Type getOwnerType();
}
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 返回確切的泛型引數, 如Map<String, Integer>返回[String, Integer]
        Type type = ((ParameterizedType) superclass).getActualTypeArguments()[0]; 
        System.out.println(type);//class java.lang.String
    }
}

10,虛擬機器是如何實現泛型的

Java泛型是Java1.5之後才引入的,為了向下相容。Java採用了C++完全不同的實現思想。Java中的泛型更多的看起來像是編譯期用的
Java中泛型在執行期是不可見的,會被擦除為它的上級型別。如果是沒有限定的泛型引數型別,就會被替換為Object.

C++中GenericClass<String>和GenericClass<Integer>是兩個不同的型別
Java進行了型別擦除之後統一改為GenericClass<Object>

三,學以致用

1,泛型解析JSON資料封裝

api返回的json資料

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

 * Description: 介面資料接收基類
 */
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;
    }
}


 * Description: 使用者資訊介面實體類
 */
public class UserResponse<T> extends BaseResponse {
    private T data;

    public T getData() {
        return data;
    }

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

2,泛型+反射實現巧複用工具類

 * Description: 泛型相關的工具類
 */
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());
    }

    /**
     * 對任意集合的排序方法
     * @param targetList 要排序的實體類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);
    }
}