2011-07-28 134 views
4

泛型方法按如下:泛型方法有限制类型参数和类型擦除

static <E, K extends E> void someMethod(K k, E[] e) {} 

我擦除时认为,擦除类型是:

static void someMethod(Object k, Object[] e) {} 

只是好奇,怎么会有类型参数知道类型擦除后的约束?那个类型参数K是有界的E?

回答

8

你对擦除是正确的。实际上,运行时并不知道约束条件。只有编译器才会。

+3

否则它不会被非常消除。 –

2

您的类型擦除签名是正确的。但是,编译过程中方法的约束不会被擦除。它们被编码在编译时使用的元数据中(并且通常在运行时使用,尽管它可以通过反射*进行访问)。例如,类java.util.ArrayList<E>有方法:

public E get(int index) 

与类型擦除变为:

public Object get(int index) 

然而,在你的代码,如果你参数ArrayListString那么你会调用get(...)方法不需要将结果转换为String,尽管进行了类型擦除。

这与参数化类或方法调用时发生的情况不同。提供的参数在编译时完全擦除。例如:

ArrayList<String> myList = new ArrayList<String>(); 

编译后相当于:

ArrayList myList = new ArrayList(); 

*通过反射在运行时访问这些信息都可以通过使用反射方法,返回java.lang.reflect.Type实例来完成。例如,要在运行时获取方法的约束,可以调用java.lang.reflect.MethodgetGenericParameterTypes()方法。处理这些返回的信息可以在运行时确定约束条件。

2

我要指出的是,其实,你的类型约束

static <E, K extends E> void someMethod(K k, E[] e) {} 

完全相同相同的效果(在编译时)作为

static void someMethod(Object k, Object[] e) {} 

尝试调用someMethod("foo", new Integer[3])如果你不”不相信我。

这是因为它是有效的,编译器推断Object作为既EK(参数,因为任何K对象也是Object一个实例,任何E[]对象也是Object[]一个实例(记住,阵列类型在Java中是协变的))。

这是Java泛型中常见的错误。例如,Arrays.fill()方法的签名为static void fill(Object[] a, Object val);他们不可能进一步限制它。