1

鉴于以下情况

class Base { }
class Extended extends Base {}

我可以很容易地在泛型类的构造函数中请求一个类对象,它是泛型类型的某个子类

class Test<T extends Base> {
  Test(Class<? extends T> test) { }
}

这样我就可以做到以下所有

new Test<Base>(Base.class);
new Test<Base>(Extended.class);
new Test<Extended>(Base.class); // This is not allowed by the compiler
new Test<Extended>(Extended.class);

这正是我想要的。但是,当使用这样的通用方法时,我无法弄清楚如何实现相同的约束:

<T extends Base> void test(T x, Class<? extends T> test) { }

使用此定义,编译器允许以下所有内容:

test(new Base(), Base.class);
test(new Base(), Extended.class);
test(new Extended(), Base.class); // even though Base is not a subclass of Extended
test(new Extended, Extended.class);

我认为这是因为类型推断和 Java 确定

<Base>test(new Extended(), Base.class)

代替

<Extended>test(new Extended(), Base.class)

但是我怎样才能强制执行后一种推理方法呢?

感谢帮助!

对于未来的读者:在这个问题的第一个版本中,我调用了Base Aand Extended B。我后来澄清了这个符号。然而,这个符号在答案中使用。

4

4 回答 4

0

泛型不是为了施加任意的“限制”。泛型仅用于类型安全,即避免不安全的强制转换。您提出的限制没有类型安全的理由。没有功能test可以test(new Base(), Base.class);是类型安全的,但test(new Extended(), Base.class);不会。

于 2013-06-26T07:42:42.220 回答
0

这是计算机科学中的一个问题,因此可以通过另一个间接级别来解决

<T extends A, U extends T> void test(T x, Class<U> test) {}

在这种情况下,我们使用一个类型变量(绑定到 A)来捕获对象参数的类型,并使用第二个(绑定到第一个)来约束类参数的类型。

如果我写出这个例子并将其提供给 javac (1.6.0_26),它会及时告诉我:

Test.java:14: cannot find symbol
symbol  : method test(B,java.lang.Class<A>)
location: class Test<T>
        test(b, A.class);
        ^
1 error

正如@JohnB 在他的评论中暗示的那样,您可以通过编写以下内容来击败它:

this.<A, A>test(b, A.class);

或者通过使用原始类型。

于 2013-06-25T11:54:38.083 回答
0

好的,我将分两部分尝试。首先,我认为你不能做你想做的,因为调用者总是可以将超类指定为泛型,然后将子类作为第一个参数传递。

其次,我认为尝试将其作为编译时检查是错误的方法,因为用户总是可以选择使用原始类型而忽略所有泛型。您应该将此作为运行时检查并提供适当的文档。

于 2013-06-25T12:01:03.937 回答
-1

我相信答案是,在第一种情况下,您指定了泛型类型:new Test<B>(...). 注意<B>. 但是在第二种情况下,您没有指定泛型类型:test(a, A.class)因此您允许编译器查看它是否可以确定一个有效的泛型类型。在 的情况下test(b, A.class)<A>因为b是 的一个实例而有效A

尝试类似:myInstance.<B>test(b, A.class)

于 2013-06-25T11:46:04.877 回答