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