從頭認識java-13.11 對比數組與泛型容器,觀察類型擦除給泛型容器帶來什麼問題?
這一章節我們繼續類型擦除的話題,我們將通過對比數組與泛型容器,觀察類型擦除給泛型容器帶來什麼問題?
1.數組
package com.ray.ch13;public class Test {public static void main(String[] args) {Fruit[] fruits = new Apple[5];fruits[0] = new Apple();fruits[1] = new Fuji();fruits[2] = new Fruit();}}class Fruit {}class Apple extends Fruit {}class Fuji extends Apple {}觀察上面的代碼,我們可以看到,雖然定義只是Fruit 的數組,但是它可以放進去Apple、Fuji等子類型的對象,因為數組是持有對象的引用,而且可以在運行時向上轉型。
2.泛型容器
一般用法:
package com.ray.ch13;import java.util.ArrayList;public class Test {public static void main(String[] args) {ArrayList fruits = new ArrayList();fruits.add(new Fruit());fruits.add(new Apple());fruits.add(new Fuji());}}class Fruit {}class Apple extends Fruit {}class Fuji extends Apple {}
上面是我們的常用用法,定義一個List容器,泛型裡面填寫的是同一個類型。
但是,我們下面將根據向上轉型的特性,看看能不能像數組一樣?
例子:
package com.ray.ch13;import java.util.ArrayList;public class Test {public static void main(String[] args) {// ArrayList fruits = new ArrayList();//errorArrayList fruits = new ArrayList(); // fruits.add(new Apple());//error// fruits.add(new Fruit());//errorfruits.add(null);// 這裡只能是null,沒有其他選擇}}class Fruit {}class Apple extends Fruit {}class Fuji extends Apple {}觀察上面的代碼,本來我們想跟數組一樣,在建立list的時候只是把泛型定義為Fruit的子類,但是,編譯器拋異常。這是因為泛型不是完全定義,它只是在編譯器檢查型別安全,在運行期就沒有泛型的概念了。而當我們定義的時候是通過萬用字元“?”來定義,也就是說我可以放進去Fruit的本身或者子類,編譯器可以知道,但是在運行期,jvm只是知道放進來Object,而在建立的時候是定義了Apple子類,雖然編譯器知道,但是在運行期,jvm也只是知道放進來Object,這個時候在運行期就會引起型別安全的問題,因此,當我們放進去什麼對象都會引起型別安全的時候,編譯器只能給出null這個選項,不然就必然會出現型別安全的風險。
總的來說,因為數組是完全定義,在編譯器和運行期都會進行類型檢測,或者說數組本身就是持有對象,而泛型容器只是在編譯器檢查型別安全,而在運行期全是Object,只是半定義,或者說泛型容器不持有對象,才導致上面所展示的問題。
總結:這一章節我們主要對比數組與泛型容器,觀察類型擦除給泛型容器帶來什麼問題。
這一章節就到這裡,謝謝。