JAVA泛型容器的型別檢查
泛型容器是通過指定容器包含物件的型別,由編譯器保證物件型別的正確性,在編譯階段就能檢查出型別錯誤。如下列將List<Long>物件longList賦予一個List<GenericTest>物件gtList,會報編譯錯誤。
publicclassGenericTest
{
publicstaticList<Long>longList= Arrays.asList (1L ,2L);
publicstaticvoidmain(String args[]){
//下面這條語句編譯會報錯
List<GenericTest> gtList=
}
}
如果這只是在編譯檢查,那麼我們是否可以繞過編譯檢查呢?我們先將List<Long>物件longList賦予一個raw List變數rawList,然後再將這個rawList強制型別轉換成List<GenericTest>型別。結果編譯通過了,並且執行時也沒有報錯。我們成功地騙過了編譯器。
publicclassGenericTest
{
publicstaticList<Long>longList= Arrays.asList (1L ,2L);
publicstaticvoidmain(String args[]){
List rawList=longList;
//這個是可以編譯通過,成功的騙過了編譯器
List<GenericTest> gtList= rawList;
}
}
接著,如果我們使用List<GenericTest>型別的變數gtList,那會發生什麼事。注意gtList引用的容器裡面放的實際上是Long型別物件。這會發生什麼事,會引用一段錯誤的記憶體嗎?結果我們發現String result = gtList.get(0).stringValue;語句正確地在執行時丟擲 java.lang.ClassCastException
publicclassGenericTest
{
publicstaticList<Long>longList= Arrays.asList (1L ,2L);
public StringstringValue ="ss";
publicstaticvoidmain(String args[]){
List rawList=longList;
//這個是可以編譯通過,成功的騙過了編譯器
List<GenericTest> gtList= rawList;
//會在執行時丟擲java.lang.ClassCastException
String result =gtList.get (0).stringValue;
}
}
位元組碼分析如下:
0 getstatic #28<variable/GenericTest.longList> //獲得類變數longList, 並放入棧頂
3 astore_1 //將棧頂引用放入第一個本地變數 rawList
4 aload_1 //將第一個本地變數rawList,放入棧頂
5 astore_2 //將棧頂引用放入第二個本地變數tgList,這裡我們可以看到將rawList賦值給tgList,沒有任何型別檢測,所以執行通過
6 aload_2
7 iconst_0
8 invokeinterface #43<java/util/List.get> count 2
13 checkcast #1 <variable/GenericTest> // 檢測型別轉換,當我們使用容器中物件時,會有型別檢測,導致丟擲java.lang.ClassCastException
16 getfield #37<variable/GenericTest.stringValue> // 獲得例項屬性,並放入棧頂
19 astore_3 //將棧頂引用放入第三個本地變數 result
20 return