2016-03-15 65 views
0

雖然經歷對Java反射和泛型一些Jakov的Jenkov博客,我發現了以下一段話:Java泛型和反射(jenkov博客)

當運行時檢查一個參數化類型本身,像java.util.List,沒有知道什麼類型已被參數化的方法。這是有道理的,因爲類型可以被參數化爲同一應用程序中的各種類型。但是,當您檢查聲明使用參數化類型的方法或字段時,您可以在運行時查看可參數化類型參數化的類型。

任何人都可以請詳細說明該段?

我被聲明「時,運行時檢查一個參數化類型本身」糊塗

回答

3

考慮下面的小程序:

import java.util.ArrayList; 

class MyClass { 
    ArrayList<String> stringList; 

    public ArrayList<String> getStringList() { 
     return stringList; 
    } 
} 

public class Foo { 
    public static void main(String... args) throws NoSuchMethodException { 
     ArrayList<Integer> intList = new ArrayList<>(); 
     System.out.println(intList.getClass().toGenericString()); 
     System.out.println(MyClass.class.getMethod("getStringList").toGenericString()); 
    } 
} 

該程序的輸出:

public class java.util.ArrayList<E> 
public java.util.ArrayList<java.lang.String> MyClass.getStringList() 

正如你看到的,事實上,intListArrayList<Integer>在運行時是不知道,但MyClass.getStringList()返回ArrayList<String>的事實是。

的原因是,所有ArrayList實例(其中的一些可以是ArrayList<Integer> S和其他ArrayList<String> S)共享相同的Class對象:

ArrayList<String> stringList = new ArrayList<>(); 
ArrayList<Integer> intList = new ArrayList<>(); 
System.out.println(stringList.getClass() == intList.getClass()); 

將輸出true。所以intList.getClass()無法知道任何關於對象的類型參數。

在另一方面,通過MyClass.getStringList()返回的對象始終是一個字符串列表,這些信息都可以在運行時可以看到。

0

在Java泛型是編譯時的事情。沒有辦法在運行時獲得有關泛型類型的任何信息,但非空對象包含有關它們類型的信息。

所以,如果你有一個方法,即採取List<T>和列表不爲空,可以讓這樣的事情:

if (list.get(0) instanceOf X) { // ... }

如果你看過泛型一些Java代碼,你」 LL發現有很多方法,如認爲:

<T> T getSomething(Class<T> aClass); 

究其原因,爲什麼需要一些對象,攜帶型,是,有沒有這樣的事情泛型類型在運行在所有。

+0

某些通用信息在編譯器需要它檢查您的代碼時可用,例如,字段,方法參數,方法返回類型,超類和接口。除非通過上述手段之一間接進行,否則不能通過對象獲得。 –

+1

@PeterLawrey你也許是對的,但是往往很難理解那些東西的適用性邊界。 你的意思是這樣嗎? http://stackoverflow.com/a/3403976/1240328 –

+0

是的,代碼中的信息可以通過反射獲得。但是,實例中沒有附加信息。 –

0

簡而言之,它只是聲明列表不知道它保存的是什麼類型的數據。當你調用一個方法時,程序會在運行時找出它的類型。

1

想想看,你有下面的類:

public class ReflectionTest { 
    List<Integer> list1 = new ArrayList<>(); 
    List<String> list2 = new ArrayList<>(); 
} 

檢查參數化類型本身就意味着檢查list1.getClass()list2.getClass()。他們絕對是不可區分的:

System.out.println(list1.getClass() == list2.getClass()); 
// prints true 

ArrayList所有實例都是同一個類的實例,無論參數化的,所以有剛剛list1.getClass()list2.getClass()你沒有辦法判斷它是否是參數化IntegerString

但是,如果你有到外地的直接訪問,你可以做到這一點:

System.out.println(ReflectionTest.class.getDeclaredField("list1").getGenericType()); 
// prints java.util.List<java.lang.Integer> 
System.out.println(ReflectionTest.class.getDeclaredField("list2").getGenericType()); 
// prints java.util.List<java.lang.String> 

因爲在這裏你所訪問的領域本身的實際參數與現場申報存儲在類文件一起。如果您檢查方法參數或返回值,則可能發生同樣的情況:它的實際通用簽名與擦除簽名一起也存儲在類文件中。