鉴于以下情况
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
A
和Extended
B
。我后来澄清了这种表示法。然而,在答案中使用了这种表示法。
答案 0 :(得分:0)
这是计算机科学中的一个问题,因此,can be solved by another level of indirection:
<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);
或者使用原始类型。
答案 1 :(得分:0)
好的,我将分两部分来试试。首先,我认为你不能做你想要的,因为调用者总是可以指定超类作为泛型,然后传递一个子类作为第一个参数。
其次,我认为尝试将其作为编译时检查是错误的方法,因为用户总是可以选择使用原始类型并忽略所有泛型。您应该将其作为运行时检查并提供适当的文档。
答案 2 :(得分:0)
泛型不是强加任意“限制”。泛型仅用于类型安全,即避免不安全的演员表。没有类型安全的理由要求您提供限制。没有test
函数test(new Base(), Base.class);
是类型安全的,但test(new Extended(), Base.class);
不是。
答案 3 :(得分:-1)
我相信答案是,在第一种情况下,您指定泛型类型:new Test<B>(...)
。请注意<B>
。但是在第二种情况下,您没有指定泛型类型:test(a, A.class)
因此您允许编译器查看它是否可以确定有效的泛型类型。对于test(b, A.class)
,<A>
有效,因为b
是A
的实例。
尝试类似:myInstance.<B>test(b, A.class)