如何在运行时创建泛型Collection <t>?</t>

时间:2013-06-04 21:08:48

标签: java generics

我正在编写一个方法,用“Predicate”过滤特定的Collection,并返回一个只包含过滤元素的新Collection(Predicate返回true的那些)。

这样的事情:

    public <T> Collection<T> filter(Collection<T> collection, Closure<T> predicate);

我知道,在Java中,由于类型擦除,我不能在运行时创建新的Collection()

我也通过将一个额外参数传递给方法来调用T.newInstance()来了解“解决方法”。

这看起来像是:

    public <T> Collection<T> filter(Class<? extends Collection<T>> collectionToInstanciate, Collection<T> collection, Closure<T> predicate) {

        // create the new Collection
        Collection<T> container = collectionToInstanciate.newInstance();

        // and then add only filtered items
        Iterator<T> iter = collection.iterator();
        while (iter.hasNext()) {
            T obj = iter.next();

            // if Predicate.invoke() returns true, then keep element, otherwise skip it
            if (predicate.invoke(obj)) {
                container.add(obj);
            }
        }
        return container;
    }

但是我应该如何调用我的方法?

例如,如果我只想要奇数列表的整数,我想这样做:

    // instanciate ArrayList<Integer> = [1, 2, 3, 4, 5]
    ArrayList<Integer> array = ...;

    // return a new LinkedList<Integer> with only odd numbers
    filter(LinkedList<Integer>.class, array, new Closure<Integer>() {
        public Boolean invoke(Integer arg_p) {
            return (arg_p % 2 == 0);
        }
    });

    // should return [2, 4] as a LinkedList<Integer>

问题在于

    LinkedList<Integer>.class 

无法编译。

我应该如何声明在filter()方法中正确实例化LinkedList?

此致

2 个答案:

答案 0 :(得分:3)

泛型是一个编译时功能,在运行时没什么意义。如果要创建LinkedList,就是这样做的。你不能让编译器根据你在运行时做的事情给你一个错误。

更简单的解决方案是传递要填充的类的实例。

List<Integer> result = filter(new LinkedList<Integer>(), array, 
    new Predicate<Integer>() {
        public boolean invoke(Integer arg_p) {
            return (arg_p % 2 == 0);
        }
    });

它略短,可以在编译时检查。

注意:许多这些谓词作为普通循环更简单,更快。

List<Integer> result = new LinkedList<Integer>();
for(Integer i: array)
    if (i % 2 == 0)
        result.add(i);

答案 1 :(得分:0)

从Peter Lawrey的回答和LuiggiMendoza的评论中,另一种方法是以这种方式使用filter()方法:

    List<Integer> result = filter(
        LinkedList.class, // instead of new LinkedList<Integer>()
        array, 
        new Predicate<Integer>() {
            public boolean invoke(Integer arg_p) {
                return (arg_p % 2 == 0);
            }
        });

在filter()方法中:

    public <T> Collection<T> filter(Class<? extends Collection> collectionToInstanciate, Collection<T> collection, Closure<T> predicate) {

    // create the new Collection as a raw Collection, and cast it back to Collection<T>
    Collection<T> container = (Collection<T>) collectionToInstanciate.newInstance();

    // and then add only filtered items
    Iterator<T> iter = collection.iterator();
    while (iter.hasNext()) {
        T obj = iter.next();

        // if Predicate.invoke() returns true, then keep element, otherwise skip it
        if (predicate.invoke(obj)) {
            container.add(obj);
        }
    }
    return container;
}