上一篇 介紹了泛型最基本的用法,泛型類和泛型方法。 這篇將繼續慢慢的解開泛型的面紗。 類型限定 有的時候方法或者類為了一些需求需要對泛型的的類型做出 一些限定。 假如:有一個類對象ArrayList中的的每一個元素實現了AutoCloseable,想要把他們全部關閉,可以如下寫 類型的變異和通配符 ...
上一篇 介紹了泛型最基本的用法,泛型類和泛型方法。
這篇將繼續慢慢的解開泛型的面紗。
類型限定
有的時候方法或者類為了一些需求需要對泛型的的類型做出 一些限定。
假如:有一個類對象ArrayList中的的每一個元素實現了AutoCloseable,想要把他們全部關閉,可以如下寫
public static <T extends AutoCloseable> void clossAll(ArrayList<T> elems)throws Exception{ for (T elem : elems) { elem.close(); } }
類型的變異和通配符
備用實體:
//人 public class Perion {} //雇員 public class Employee extends Perion{} //其他 public class Employee extends Perion{} //經理 public class Manager extends Employee {}
子類通配符
/** * 讀取ArrayList<? extends Employee> 對象中的每一個元素 * @param staffs */ public static void printName(ArrayList<? extends Employee> staffs){ for (int i = 0; i < staffs.size();i++){ Employee employee = staffs.get(i); System.out.println(employee.getName()); } } /** * 修改操作 * 錯誤實例 不能編譯通過 * add(capture<? extends genericity.gen4.Employee>)in ArrayList cannot be applied to (genericity.gen4.Employee) * @param staffs */ public static void add(ArrayList<? extends Employee> staffs){ Employee employee = new Employee("15", "測試"); staffs.add(employee); }
通過上面兩個例子可以總結:可以將 <? extends Employee>轉化成Employee但是不能將任何對象轉化成Employee。可以限定返回值。可讀。
父類型通配符
/** * 父類通配符 * @param employees */ public static void add2(ArrayList<? super Employee> employees){ Employee e = new Employee(); Manager m = new Manager(); employees.add(e); employees.add(m); //不能變譯通過 // employees.add(new Other());
for (int i = 0;i < employees.size();i++){
//super 不能限制返回值 所以必須Object
Object obj = employees.get(i);
} } public static void main(String[] args) { ArrayList<? super Employee> es = new ArrayList<Employee>(); //不能變譯通過 // List<? super Employee> es2 = new ArrayList<Manager>(); add2(es); }
可以看出super 可用於參數類型限定,不能用於返回類型限定。參數限定於Employee主幹上。可寫。
無限定通配符
/** * 無限定通配符 */ public static boolean hasNulls(ArrayList<?> elements){ for (Object element : elements) { if(element == null){ return true; } } return false; }
在某些情況下需要作非常通用的功能,可能會用到無限定通配符,如上檢查ArrayList是否包含null值元素,由於ArrayList的類型是無關緊要的,所以使用ArrayList<?>完全可以。
帶類型變數的通配符
/** * 帶類型變數的通配符 *限制Predicate的參數和方法的類型參數完全匹配 ? super T * @param elements * @param filter * @param <T> */ public static <T> void printAll2(T[] elements ,Predicate<? super T> filter){ for (T e : elements) { if(filter.test(e)){ System.out.println(e.toString()); } } }
public interface Predicate<T> { /** * * @param arg * @return */ boolean test(T arg); }
可以看出統配的限定是一個類型的變數。