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