将Class作为参数传递给返回该Class对象的ArrayList方法

时间:2017-09-29 02:10:25

标签: java generics arraylist

我有超类对象的ArrayList,并编写了这个方法来返回其子类之一的ArrayList。

public static ArrayList<SubClass> getSubClass(ArrayList<SuperClass> superObjects){
    ArrayList<SubClass> objects = new ArrayList<>();
    for (SuperClass superObject : superObjects) {
        if (superObject instanceof SubClass) {
            objects.add((SubClass) superObject);
        }
    }
    return objects;
}

现在我想调用一个类似的方法从超类对象的同一ArrayList中提取不同子类的对象。有没有办法将这个代码概括为一个Class作为参数并返回该子类的对象的ArrayList?

1 个答案:

答案 0 :(得分:3)

如果您传入课程,则可以执行此过滤,然后调用Class.isInstance()。这称为 runtime type token 。这是一个包含流和List接口的版本:

public <T> List<T> filterList(List<? super T> list, Class<T> subClass) {
    return list.stream().
            filter(o -> subClass.isInstance(o)).
            map(o -> (T) o).
            collect(Collectors.toList());
}

如果您真的想使用ArrayList,则需要手动过滤:

public <T> ArrayList<T> filterList(List<? super T> list, Class<T> subClass) {
    ArrayList<T> result = new ArrayList<>();
    for (Object obj : list) {
        if (subClass.isInstance(obj)) {
            result.add((T) obj);
        }
    }
    return result;
}

你可以这样测试:

    List<Number> nums = new ArrayList<>();
    nums.add(1);
    nums.add(2);
    nums.add(3L);
    nums.add(4L);
    nums.add(5.0F);
    nums.add(6.0F);
    nums.add(7.0);
    nums.add(8.0);

    List<Integer> ints = filterList(nums, Integer.class);

    // prints [1, 2]
    System.out.println(Arrays.toString(ints.toArray()));

运行时类型令牌是泛型的常用习惯用法。例如。 EnumMap也使用它:

private static enum Foo {One, Two, Three}
Map<Foo, Integer> map = new EnumMap(Foo.class);

更新

根据@Valentin Ruano的评论,这是一个简洁且无警告的基于流的过滤器:

public <T> ArrayList<T> filterList(List<? super T> list, Class<T> subClass) {
    return list.stream().
    return list.stream().
            filter(o -> subClass.isInstance(o)).
            map(o -> subClass.cast(o)). // warning-free casting
            collect(Collectors.toCollection(ArrayList::new)); // forcing an ArrayList collector
}
相关问题