所以我有一个Tuple2
课程如下:
public final class Tuple2<T1, T2> {
private final T1 mItem1;
private final T2 mItem2;
public T1 getItem1() { return mItem1; }
public T2 getItem2() { return mItem2; }
public Tuple2(final T1 pItem1, final T2 pItem2) {
mItem1 = pItem1;
mItem2 = pItem2;
}
public static <TItem1, TItem2> Tuple2<TItem1, TItem2>
Create(final TItem1 pItem1, final TItem2 pItem2) {
return new Tuple2<>(pItem1, pItem2);
}
}
我试图实例化List
Tuple2
,但类型推断似乎很奇怪。我希望我能做到这样的事情:
// doesn't work
// note that Type2 extends Type1, and Type3 extends Type2
final List<Tuple2<String, Class<?>>> list = Arrays.asList(
Tuple2.Create("1", Type1.class),
Tuple2.Create("2", Type2.class),
Tuple2.Create("3", Type3.class)
);
// still doesn't work
final List<Tuple2<String, Class<? extends Type1>>> list = Arrays.asList(
Tuple2.Create("1", Type1.class),
Tuple2.Create("2", Type2.class),
Tuple2.Create("3", Type3.class)
);
如果我转投Class<?>
或Class<? extends Type1>
,这些都不起作用。
它要求我做的是:
final List<Tuple2<String, ? extends Class<? extends Type1>>> list = Arrays.asList(
Tuple2.Create("1", Type1.class),
Tuple2.Create("2", Type2.class),
Tuple2.Create("3", Type3.class)
);
但是如果我想定义对这些Tuple2
之一的引用我必须写:
final Tuple2<String, ? extends Class<? extends Type1>> item = list.get(0);
这是一个丑陋的名字......有没有办法简化这个?为什么它必须是Tuple2
&#34;延伸Class
扩展Type1
&#34;的东西,而不仅仅是{{1}某事&#34;?
我发现的唯一更简单的方法是使用Class
原始类型,这似乎是不鼓励的,需要一些演员:
Class
答案 0 :(得分:1)
这是旧的generic invariance再次抬头。
对于Create
的每次调用,类型都推断为:
<String, Class<Type1>>
<String, Class<Type2>>
<String, Class<Type3>>
如您所知,List<Dog>
不是List<Animal>
,同样的概念适用于此。 Tuple2<String, Class<Type1>>
不是Tuple2<String, Class<?>>
,而是Tuple2<String, ? extends Class<?>>
。
因此对于三种推断的Tuple2
类型:
Tuple2<String, Class<Type1>>
Tuple2<String, Class<Type2>>
Tuple2<String, Class<Type3>>
他们的共同点是Tuple2<String, ? extends Class<? extends Type1>>
。
据我所知,解决这个问题的唯一方法是为每次通话提供一个类型见证:
final List<Tuple2<String, Class<?>>> list = Arrays.asList(
Tuple2.<String, Class<?>>Create("1", Type1.class),
Tuple2.<String, Class<?>>Create("2", Type2.class),
Tuple2.<String, Class<?>>Create("3", Type3.class)
);
这应该有效。
似乎应该工作:
final List<Tuple2<String, Class<?>>> list = Arrays.asList(
Tuple2.Create("1", (Class<?>)Type1.class),
Tuple2.Create("2", (Class<?>)Type2.class),
Tuple2.Create("3", (Class<?>)Type3.class)
);
但它没有编译。编译器确实捕获转换并将Class<?>
推断为Class<capture of ?>
。因此,您最终得出的推断类型如下:
<String, Class<capture #1 of ?>>
<String, Class<capture #2 of ?>>
<String, Class<capture #3 of ?>>
还有三种截然不同的类型。
我会诚实地说:我不知道它为什么会这样运作,只是它确实如此。我一直无法找到明确的答案。 The spec says this:
- 如果T i 是形式为?的通配符类型参数[...],那么S i 是 fresh 类型变量[...]。
这似乎暗示capture of ?
被视为新类型,与?
不同。
在我看来,从版本7开始,推断与通配符之间存在差距。