【问题标题】:Passing a Class as an argument to a method that returns and ArrayList of objects of that Class将类作为参数传递给返回该类对象的 ArrayList 的方法
【发布时间】:2017-09-29 02:10:24
【问题描述】:

我有超类对象的 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?

【问题讨论】:

  • 你可以传入子类型的类并使用它,但我觉得你可能没有正确使用泛型。如果您需要SubClass 的列表,请创建一个并使用它。如果您需要一个仅取决于SuperClass 行为的列表,请改用它。

标签: java generics arraylist


【解决方案1】:

如果你传入一个类,你可以做这个过滤器,然后调用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 的 cmets,这是一个简洁且无警告的基于流的过滤器:

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
}

【讨论】:

  • 如果他想返回一个 ArrayList 而不是任何 List 则不需要“手动过滤器”,您可以定义自己的收集器。事实上,Collectors.toList() 实际上是在后台返回 ArrayList 实例,因此您可以简单地复制代码。
  • 所以,这只是第一个解决方案的弃用? (没有双关语)不过我不想依赖这种无证行为。
  • 不,我并不是建议您必须将盲法投射到 ArrayList 中...... Collectors.toList() 实现将来可能会发生变化,这将不再是真的。但是,您可以将当前的 Collectors.toList() 或其等效调用复制到更通用的 Collectors 方法,而无需将其向上转换为 List,因此将其保留为 ArrayList...我的意思是您 不要 需要 放弃使用流,以便在您回答时返回 ArrayList。
  • 查看收集器代码这可能就像使用 Collectors.toCollection(ArrayList::new) 一样简单
  • .map(o -&gt; (T) o) 也可以是 .map(subClass::cast),这可能会避免未经检查的强制转换警告。
猜你喜欢
  • 2022-01-22
  • 1970-01-01
  • 2018-06-23
  • 2019-11-27
  • 2014-12-27
  • 2022-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多