泛型(四)类型通配符
一、类型通配符
1.1、下面的程序演示了一种需求:定义一个方法,该方法有一个集合形参,但是形参的元素类型是不确定的
public static void main(String[] args) { // 想要遍历打印List<String> list1,定义一个方法,比如print1() List<String> list = new ArrayList<>(); list.add("aaa"); list.add("bbb"); print1(list); // 现在想要遍历打印List<Integer> list2,就要重新定义一个方法,比如print2() List<Integer> list2 = new ArrayList<>(); list2.add(111); list2.add(222); print2(list2); } public static void print1(List<String> list) { for (String str : list) { System.out.println(str); } } public static void print2(List<Integer> list) { for (Integer i: list) { System.out.println(i); } }
1.2、使用类型通配符可以解决:List<?> list
public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("aaa"); list.add("bbb"); print3(list); List<Integer> list2 = new ArrayList<>(); list2.add(111); list2.add(222); print3(list2); } public static void print3(List<?> list) { for (Object obj : list) { System.out.println(obj); } }
1.3、使用类型通配符的局限性(弊端)
声明List<?> list后,不能向集合中添加元素,因为无法确定集合的元素类型。唯一例外的是null,它是所有引用类型的实例。
public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("aaa"); list.add("bbb"); print3(list); } public static void print3(List<?> list) { // list.add("ccc"); // 错误,由于不知道元素的类型所以无法将 "ccc" 添加进集合 // list.add(111); // 错误,由于不知道元素的类型所以无法将 111 添加进集合 // list.add(new Object()); // 错误,由于不知道元素的类型所以无法将Object对象添加进集合 list.add(null); // 没问题 for (Object obj : list) { System.out.println(obj); } }
public static void main(String[] args) { List<?> list = new ArrayList<>(); // list.add("ccc"); // 错误,由于不知道元素的类型所以无法将 "ccc" 添加进集合 // list.add(111); // 错误,由于不知道元素的类型所以无法将 111 添加进集合 // list.add(new Object()); // 错误,由于不知道元素的类型所以无法将Object对象添加进集合 list.add(null); // 没问题 }
另一方面,可以调用get()方法来返回List<?>集合指定索引的元素,虽然不知道元素的类型,但是可以确定的是,元素一定是Object类型。
public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("aaa"); list.add("bbb"); list.add(null); print3(list); } public static void print3(List<?> list) { // 可以调用get()方法返回集合的元素 for (int i =0; i < list.size(); i++) { Object obj = list.get(i); System.out.println(obj); } }
总结:当使用通配符时,对泛型类中的参数为泛型的方法起到副作用,不能再使用。对于返回值为泛型的方法,只能赋值给Object类型变量。
二、类型通配符的限定
2.1、指定类型通配符的上限 -- 返回值为泛型的方法可以使用了
public static void main(String[] args) { List<Integer> intList = new ArrayList<>(); List<Long> longList = new ArrayList<>(); print(intList); print(longList); } // ? extends Number:指定通配符的上限,即调用本方法传递的List后尖括号里的类型只能是Number及其子类 public static void print(List<? extends Number> list) { // 因为调用本方法时传递的实参可能是List<Long>也可能是List<Integer>或其他,即还是不能确定实参具体的类型,所以下面代码错误 // list.add(new Integer("100")); list.add(null); // 没问题 // 可以调用get()方法返回集合的元素 for (int i =0; i < list.size(); i++) { Number obj = list.get(i); System.out.println(obj); } }
2.2、指定类型通配符的下限 -- 参数为泛型的方法可以使用了
public static void main(String[] args) { List<Integer> intList = new ArrayList<>(); List<Number> numList = new ArrayList<>(); List<Object> objList = new ArrayList<>(); print(intList); print(numList); print(objList); } // ? super Number:指定通配符的下限,即调用本方法传递的List后尖括号里的类型只能是Integer及其父类 public static void print(List<? super Integer> list) { // 参数为泛型的方法可以使用了 list.add(new Integer("100")); // list.add(new Object()); // 错误 list.add(null); // 没问题 // 返回值为泛型的方法还是不能使用(或说是只能赋值给Object类型) for (int i =0; i < list.size(); i++) { // Integer obj = list.get(i);// 错误 Object obj = list.get(i); System.out.println(obj); } }
总结:
posted on 2019-05-16 23:04 wenbin_ouyang 阅读(542) 评论(0) 编辑 收藏 举报