Java通配符帮助Class <t>到List <class <t>&gt;,可能吗?

时间:2016-07-03 22:14:55

标签: java list object search wildcard

我很久没有编码了,并且用通配符失去了控制力。

我有这个整洁的小功能,效果很好

public static <T> ArrayList<T> GetObjects(List<?> list, Class<T> c){
    ArrayList<T> objects = new ArrayList();     
    for(Object o : list){
        if(c.isInstance(o)){
            objects.add(c.cast(o));
        }
    }       
    return objects;
}

但是我希望它能够接受类列表并执行类似的操作

public static <T> ArrayList<T> GetMultipleObjects(List<?> list, List<Class<T>> classes){
        ArrayList<T> objects = new ArrayList();     
        for(Object o : list){
            for(Class c : classes){
            if(c.isInstance(o)){
                objects.add(c.cast(o));
            }
            }
        }       
        return objects;
    }

事后看来,这显然是不可能的。

1 个答案:

答案 0 :(得分:1)

路易斯在评论中是正确的:在Java中定义这个函数没有合理的方法。

Java没有析取类型 - 也就是说,没有办法表达类似&#34; StringInteger&#的类型的概念34 ;.你最接近的是找到一个共同的超类型 - 因为所有可实例化的类型都继承自Object(模数基元,但让我们暂时将它们放在一边),你总是可以找到一个常见的超类型,虽然它可能只是Object,但通常不是很有用。

为了说明为什么会出现这种情况,请考虑一下这个功能可以用于什么类型的事情。我看到两个案例:

案例1 :您希望过滤到类型是一个或多个类型的子类型的位置,这些类型都共享一个共同的超类型,并返回超类型的列表。您可以通过将通配符类型与类型参数一起使用来轻松完成此操作:

public static <T> List<T> filter(
    List<?> input,
    List<? extends Class<? extends T>> subtypesOfT) {
  // implementation exactly as you have it
}

但在大多数情况下,这相当于只使用原始函数并传递超类型。例如。使用原始功能,您只需传递Number.class并返回List<Number>,其中列表中的值可以是DoubleIntegerFloat。唯一有用的方法是,如果您想从List<Number>过滤出List<?>,但也只包含 Number的某些子类型。例如您可以通过asList(Double.class, Integer.class)并返回List<Number>。但我怀疑这会特别有用,特别是在这种形式的一般情况下。

案例2 :或者,您可以考虑采用List<?>并过滤它以仅包含任意一组其他类型的值。在这种情况下,除非您计算一个,否则没有T统一,所以您可以做的最好的事情是返回List<Object>(或者,如果列表是只读的,则等效于此情况,一个List<?>)。为此,您根本不需要该方法是通用的:只需使用ArrayList<Object>来构造返回值,它就可以正常工作。

如果您以足够的元编程方式执行此操作,您可能希望有一种方法来构建List<T>,其中T是所有值的最具体的常见超类型List<?>可以分配给。这也是可行的,但您首先需要找到T。这是你可以做到的一种方式:

private static Class<?> findCommonSupertype(List<Class<?>> types) {
  Class<?> result = types.get(0);
  for (Class<?> type : types) {
    // Keep going as long as result is a supertype of the current type.
    if (result.isAssignableFrom(type)) {
      continue;
    }
    // Skip interfaces since they unify with any class type (unless
    // the class is final, which we don't check for here).
    if (result.isInterface() && !type.isInterface()) {
      result = type;
    } else if (type.isInterface()) {
      continue;
    }
    // Otherwise, scan up through the inheritance hierarchy to find a
    // new type that can serve as a common supertype for type and result.
    Class<?> supertype = type;
    while (!supertype.isAssignableFrom(result)) {
      supertype = supertype.getSuperclass();
      if (supertype == null) {
        throw new IllegalArgumentException(
            type + " and " + result + " do not share a common supertype");
      }
    }
    result = supertype;
  }
  return result;
}

尽管如此,即使你有这样的功能,它仍然不会特别有用,因为你可以建立一个List<T>,但你不能静态地知道T 1}}是(因为它会动态计算),所以我不认为这是你真正想要的。