【问题标题】:Filtering List of generic object for single generic instance过滤单个泛型实例的泛型对象列表
【发布时间】:2015-09-12 05:11:50
【问题描述】:

我有一个List 类型为MyClass<T> 的通用对象,我不知道它的确切类型:List<MyClass<? extends Object>>

有没有办法过滤此列表以仅获取那些具有特定T而不使用instanceof的对象?。

我觉得这可以通过Visitor patternT 的每个特定实例的子类化来完成(例如MyClassString extends MyClass<String>,这不是问题),但我不想为每个子类实现一个访问者:

class MyClassString extends MyClass<String> {

    public <U> U accept(MyClassVisitor<U> visitor) {
        return visitor.visitMyClassString(this);
    }

}

interface MyClassVisitor<U> {

    U visitMyClassString(MyClassString myClassString);
    U visitMyClassDouble(MyClassDouble myClassDouble);
    ...

}

class FilterMyClassStringService implements MyClassVisitor<List<MyClassString>> {

    public List<MyClassString> filterMyClassString(List<MyClass<? extends Object>> toFilter) {
        List<MyClassString> filteredList = new ArrayList<>();
        for (MyClass<? extends Object> elem : toFilter) {
            filteredList.addAll(elem.accept(this));
        }
        return filteredList;
    }

    @Override
    public List<MyClassString> visitMyClassString(MyClassString myClassString) {
        List<MyClassString> listWithMyClassString = new ArrayList<>();
        listWithMyClassString.add(myClassString);
        return listWithMyClassString;
    }

    @Override
    public List<MyClassString> visitMyClassDouble(MyClassDouble myClassDouble) {
        return new ArrayList<MyClassString>();
    }

}

有什么办法吗?

【问题讨论】:

  • 如果你使用的是Java 8,你可以使用流来过滤。
  • 你能告诉我们为什么你不想使用实例吗?它很贵吗?
  • 老实说,我只是想知道是否可以做到。在许多地方反对使用instanceOf 的一个原因是很容易忘记为每个检查类型的if 添加另一个案例。访问者模式强制所有打开类型(使用访问者)的人在将新类型添加到程序时考虑它。

标签: java generics


【解决方案1】:

我想我明白你想要什么。这在某种程度上是可能的。如果我们将此线程 (How to get the generic type at runtime?) 中的讨论应用到您的案例中,那么我们将有类似以下代码:

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

public class TypedReflectTest {
    public static void main(String[] args) {
        List<MyClass<?>> list = new ArrayList<MyClass<?>>();
        list.add(new MyClassInteger(123));
        list.add(new MyClassDouble(123.45));
        list.add(new MyClassString("1234"));
        System.out.println(filterMyClass(list, Integer.class));
    }

    public static List<MyClass<?>> filterMyClass(List<MyClass<?>> toFilter, Class<?> innerType) {
        List<MyClass<?>> filteredList = new ArrayList<MyClass<?>>();
        for (MyClass<?> elem : toFilter) {
            if (!elem.getInnerType().equals(innerType))
                continue;
            filteredList.add(elem);
        }
        return filteredList;
    }
}

abstract class MyClass<T> {
    private T value;
    private Class<?> innerType;

    public MyClass(T value) {
        this.value = value;
        Type superClass = getClass().getGenericSuperclass();
        innerType = (Class<?>)(((ParameterizedType) superClass).getActualTypeArguments()[0]);
    }

    public T getValue() {
        return value;
    }

    public Class<?> getInnerType() {
        return innerType;
    }

    @Override
    public String toString() {
        return "MyClass(" + value + ")";
    }
}

class MyClassInteger extends MyClass<Integer> {
    public MyClassInteger(Integer value) {
        super(value);
    }
}

class MyClassDouble extends MyClass<Double> {
    public MyClassDouble(Double value) {
        super(value);
    }
}

class MyClassString extends MyClass<String> {
    public MyClassString(String value) {
        super(value);
    }
}

你应该注意到抽象超类在这里是必不可少的。您不能处理 MyClass 类型本身的实例。不幸的是,您必须扩展此类才能在运行时获得参数化类型。

【讨论】:

    猜你喜欢
    • 2011-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多