Java泛型和反思(jenkov博客)

时间:2016-03-15 09:08:37

标签: java generics reflection

在浏览一些有关java反射和泛型的Jakov Jenkov博客时,我发现了以下段落:

  

当运行时检查可参数化类型本身时,如java.util.List,无法知道参数化的类型。这是有道理的,因为类型可以参数化为同一应用程序中的所有类型。但是,当您检查声明使用参数化类型的方法或字段时,您可以在运行时看到参数化参数化类型的类型。

任何人都可以详细说明该段吗?

我对“当运行时检查可参数化类型本身”

时的语句感到困惑

5 个答案:

答案 0 :(得分: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>和其他ArrayList<String>)共享相同的Class对象:

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

会输出true。因此intList.getClass()无法了解对象的类型参数。

另一方面,MyClass.getStringList()返回的对象始终是字符串列表,可以在运行时看到此信息。

答案 1 :(得分: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()您无法确定它是否使用{{1}参数化}或Integer

但是,如果您可以直接访问该字段,则可以执行此操作:

String

因为在这里您正在访问字段本身,并且实际参数化与字段声明一起存储在类文件中。如果检查方法参数或返回值,则可以进行相同的操作:它的实际通用签名也会与删除的签名一起存储在类文件中。

答案 2 :(得分:0)

java中的泛型是一个编译时间的东西。没有办法在运行时获取泛型类型的任何信息,但非null 对象包含有关其类型的信息。

所以,如果你有一个方法,它需要List<T>并且列表不为空,你可以做出类似的东西:

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

如果你读了一些带有泛型的java代码,你会发现很多这样的方法:

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

原因是,为什么需要携带类型的某个对象,就是在运行时根本没有泛型类型。

答案 3 :(得分:0)

简单来说,它只是表明该列表并不知道它所拥有和不关心的数据类型。当你调用一个方法时,你的程序会找出它在运行时的类型。

答案 4 :(得分:0)

请参阅这些文章:this oneanother one以及one more

他们解释了&#34;擦除机制&#34;。