捕获方法参数类型并请求相应的类对象

时间:2013-06-25 11:37:57

标签: java generics type-inference

鉴于以下情况

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 AExtended B。我后来澄清了这种表示法。然而,在答案中使用了这种表示法。

4 个答案:

答案 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>有效,因为bA的实例。

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