Java集合與泛型中的陷阱


List,List<Object>區別

  List<Integer> t1 = new ArrayList<>();
		// 編譯通過
		List t2 = t1;
		//編譯失敗
		List<Object> t3 = t1;

t1 可以賦給 t2, 但是 t1 不能賦給 t3,會拋出如下異常

Error:(16, 35) java: 不兼容的類型: java.util.List<java.lang.Integer>無法轉換為java.util.List<java.lang.Object>

List<?>注意點

	List<Object> t1 = new ArrayList<>();
		List<?> t2 = t1;
		// 編譯通過
		t2.remove(0);
		t2.clear();
		// 編譯不通過
		t2.add(new Object());

List<?> 是一個泛型,在沒有賦值之前,是可以接受任何集合的賦值的,但是請注意,賦值之后就不能往里面添加元素了

提示如下錯誤:

Error:(18, 19) java: 對於add(java.lang.Object), 找不到合適的方法
    方法 java.util.Collection.add(capture#1, 共 ?)不適用
      (參數不匹配; java.lang.Object無法轉換為capture#1, 共 ?)
    方法 java.util.List.add(capture#1, 共 ?)不適用
      (參數不匹配; java.lang.Object無法轉換為capture#1, 共 ?)

所以 List<?> 一般用來作為參數來接受外部的集合,或者返回一個不知道具體元素的集合。

<? extends T> 與 <? super T>

<? extends T>

<? extends T> a,a 這個變量可以接受 T 及其 T 子類的集合,上界為 T,並且從 a 取出來的類型都會被強制轉換為 T

class Animal{

}

class Cat extends Animal{

}

class RedCat extends Cat{

}

demo:

	    List<Animal> animals = new ArrayList<>();
		List<Cat> cats = new ArrayList<>();
		List<RedCat> redCats = new ArrayList<>();
		// 可以通過編譯
		List<? extends  Cat> extendsCat = redCats;
		// 不能通過編譯,因為只能接受 Cat 及其子類的集合
		extendsCat = animals;

		// 重點注意:下面三行都不能通過編譯
		extendsCat.add(new Animal());
		extendsCat.add(new Cat());
		extendsCat.add(new RedCat());
		// 重點注意:可以通過編譯
		extendsCat.add(null);

<? extends T>最需要注意的是,就是不能向里面添加除null之外的其他所有元素,這個和 List<?> 有點類似

<? super T>

<? super T>,它和 <? extends T> 有點相反。**對於 <? super T> a**,a 這個變量可以接受 T 及其 T 父類的集合,下界為 T,並且從 a 取出來的類型都會被強制轉換為 Object

demo:

    List<Animal> animals = new ArrayList<>();
    List<Cat> cats = new ArrayList<>();
    List<RedCat> redCats = new ArrayList<>();
    // 可以通過編譯
    List<? super  Cat> superCat = animals;
    // 不能通過編譯,因為只能接受 Cat 及其父類的集合
    superCat = redCats;

    // 重點注意:不能通過編譯,只能添加 Cat 及其 Cat 的子類
    superCat.add(new Animal());
    // 重點注意,可以通過編譯
    superCat.add(new Cat());
    superCat.add(new RedCat());
    superCat.add(null);

注意,<? super T>最需要注意的是,在雖然可以接受 T 及其父類的賦值,但是只能向里面添加 T 及其 T 的子類

總結

1、List<? extends T> a ,可以把 a 及其 a 的子類賦給 a,從 a 里取的元素都會被強制轉換為 T 類型,不過需要注意的是,不能向 a 添加任何除 null 外是元素

2、List<? super T> a ,可以把 a 及其 a 的父類賦給 a,從 a 里取的元素都會被強制轉換為 Object 類型,不過需要注意的是,可以向 a 添加元素,但添加的只能是 T 及其子類元素

List泛型與重載

你覺得下面這道題能夠編譯通過嗎?

class GernerTypes {
	public static void  method(List<Integer> list) {
		System.out.println("List<Integer> list");
	}
	public static void method(List<String> list) {
		System.out.println("List<String> list");
	}
}

不通過編譯,錯誤信息:

Error:(20, 28) java: 名稱沖突: method(java.util.List<java.lang.String>)和method(java.util.List<java.lang.Integer>)具有相同疑符

兩個方法的參數不同,為什么會重載不通過呢?

實際上在 Java 的泛型中,泛型只存在於源碼中,在編譯后的字節碼中,泛型已經被替換為原生類型了,並且在相應的地方插入了強制轉換的代碼。

所以上面的兩個方法,看似參數不一樣,但是經過編譯擦出之后,他們的參數就是一樣的了,所以編譯不通過。

數組集合轉換:

String[] arr = {"one", "two", "three"};
		// 數組轉換成集合
		List<String> list = Arrays.asList(arr);
		// 向集合添加元素:編譯正常,但運行時拋出了異常
		list.add("four");

運行時報錯:

Exception in thread "main" java.lang.UnsupportedOperationException
	at java.util.AbstractList.add(AbstractList.java:148)
	at java.util.AbstractList.add(AbstractList.java:108)
	at com.qhong.basic.list.test.main(test.java:16)

問題來了,向集合添加元素為啥會拋出異常呢??

我們先來看一下 Arrays.asList(arr) 方法究竟返回了什么?

看源碼:

 public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

    /**
     * @serial include
     */
    private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
        private static final long serialVersionUID = -2764017481108945198L;
        private final E[] a;

        ArrayList(E[] array) {
            a = Objects.requireNonNull(array);
        }
    。。。。

返回的List內部直接引用了原數組arr

原數組長度固定為3,所以不可以再add

下面的代碼證明這一點

String[] arr = {"one", "two", "three"};
        // 數組轉換成集合
        List<String> list = Arrays.asList(arr);
        // 修改 arr
        arr[0] = "0";
        //打印看看
        System.out.println(list.get(0));

打印:

0

建議大家這樣轉換比較安全

List<String> list = new ArrayList<>(Arrays.asList(arr));

參考:

Java集合與泛型中的幾個陷阱,你掉進了幾個?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM