如何声明具有多个界限的类类型的对象

时间:2018-10-30 15:34:08

标签: java

我有一个Class<?>类型的对象,我正在尝试使用签名的方法:

<T extends A & B> void foo(Class<T> clazz);

如何声明参数以满足签名?


示例:

void bar(String type) throws Exception {

    Class<?> clazz = Class.forName(type);

    if(!clazz.isAssignableFrom(A.class)) throw new IllegalArgumentException("type="+type);
    if(!clazz.isAssignableFrom(B.class)) throw new IllegalArgumentException("type="+type);

    //We know clazz implements both A and B, how do we call foo?
    foo(clazz.asSubclass(???)); 
}

<T extends A & B> void foo(Class<T> clazz) {
    //Success
}

编辑:我将foo方法重构为<T extends A> ...并将其中的.isAssignableFrom(B.class)移动到其中。

1 个答案:

答案 0 :(得分:1)

编辑:让我以此为前提(请参见下文以获取更多信息):反射和泛型并不适合,因为它们在不同的时间运行:

  • 泛型主要是一种编译时工具,可帮助编译器发现潜在的编程错误,例如尝试将字符串添加到数字列表中
  • reflection主要是一种运行时工具,用于在运行时获取有关类/对象的信息(例如resolveClass()),由于类型擦除,大多数泛型信息在运行时会丢失

原始答案:

T extends A & B仅在B是一个接口(A可以是一个类或一个接口)并且参数必须匹配两者(即它必须是A 并实施B(假设A尚未实施B,在这种情况下,A & B部分将是不必要的)。

作为示例,我们使用NumberComparable

<T extends Number & Comparable<T>> void foo(Class<T> clazz);

我们现在可以叫foo(Long.class),因为Long extends Number implements Comparable<Long>

我们无法调用foo(AtomicInteger.class),因为AtomicInteger extends Number 但是它没有实现Comparable<AtomicInteger>

我们也无法调用foo(Number.class),因为Number匹配extends Number但未实现Comparable<Number>

在您的情况下,您需要定义一个变量Class<? extends A & B>,但不支持,因此您需要使用通用类型(在调用方法或类上定义) )或具体类型:

<T extends A & B> bar() {
  Class<T> clazz = resolveClass(); //This would need the same generic type
  foo( clazz );
}

class C extends A implements B {}

Class<C> clazz = resolveClass(); //This would need the same generic type
foo( clazz );

您可以想象这会变得非常复杂,可能不可行。 作为最后的尝试,您可以尝试使用原始类型:

Class clazz = resolveClass(); //This would need the same generic type
foo( clazz );

这会产生很多警告,因为它会禁用类型检查,因此请确保对您的参数进行了彻底检查。因此,如果您需要这样做,则可能暗示存在设计缺陷,因此,我建议您认真考虑是否需要T extends A & B以及代码在做什么。