4

假设我有一个非泛型List或 a List<Foo>,你知道它的所有元素都是 type Bar,这是一个子类Foo(总是如此)。假设您无法更改获取原始列表的代码,以便您可以List<Bar>直接获取。是否有一些图书馆或其他东西可以帮助“同质化”这个列表?

也就是说,在

public static <T, U extends T> List<U> homogenize(List<T> list, Class<U> subclass);

我可以在某处使用吗?(homogenize()返回输入列表的视图,其中的函数在适当的情况下U而不是TObject在适当的情况下接收。它不返回列表的副本。如果输入列表不能同质化 - 也就是说,如果不是所有元素的类型都可分配给U,然后homogenize()返回 null。)

4

2 回答 2

4

如果您正在寻找图书馆,我的第一个想法是使用Google Guava Libraries,如下所示:

public <T, U extends T> List<U> homogenize(List<T> list, final Class<U> subclass) {
    Predicate<T> pred = new Predicate<T>() {
        @Override
        public boolean apply(T input) {
            return input.getClass().isAssignableFrom(subclass);
        }
    };
    return Iterables.all(list, pred) ? (List<U>)list : null;
}

我还没有尝试过,以确保扭结已经消失。然而,我看着它,并认为它非常丑陋。稍微好一点的番石榴方法是:

public <T, U extends T> List<U> homogenize(List<T> list, Class<U> subclass) {
    Iterable<U> ret = Iterables.filter(list, subclass);
    if (list.size() != Lists.newArrayList(ret).size()) return null;
    return (List<U>)list;
}

但是,它仍然有点难看。它使用集合的内部副本。它仍然返回原始的演员视图。毕竟,最干净的方法似乎是使用常规 Java:

public <T, U extends T> List<U> homogenize(List<T> list, Class<U> subclass) {
    for( T t : list) {
        if (!t.getClass().isAssignableFrom(subclass)) return null;
    }
    return (List<U>)list;
}

根据您对类型转换警告的反感,您甚至可以在所有三个选项中删除转换运算符。

根据评论进行编辑评论 中提出了以下更改/改进。

选项一改进:

public <T, U extends T> List<U> homogenize(List<T> list, final Class<U> subclass) {
    return Iterables.all(list, Predicates.instanceOf(subclass)) ? (List<U>)list : null;
}

选项二改进:

public <T, U extends T> List<U> homogenize(List<T> list, Class<U> subclass) {
    Iterable<U> ret = Iterables.filter(list, subclass);
    return (list.size() != Iterables.size(ret)) ? null : (List<U>)list;
}

选项三改进:

public <T, U extends T> List<U> homogenize(List<T> list, Class<U> subclass) {
    for( T t : list) {
        if (!subclass.isInstance(t.getClass())) return null;
    }
    return (List<U>)list;
}

通过这些改进,第一个番石榴示例大放异彩。如果您不介意静态导入,则两个 Guava 示例都变得非常易读。

于 2012-08-28T04:32:08.897 回答
0

为什么不能直接投呢?

public static <U> List<U> homogenize(List<? super U> list){
    return (List<U>)list;
}

请注意,泛型是纯粹的编译时检查。如果类型不是您所期望的,那么当您尝试将不是 a 的对象强制转换为 a 时,您将得到一个bar异常bar

编辑:我没有注意到您希望它实际检查内容的类型并在失败时返回 null 。如果您不确定这些项目是正确的类型并且想要故障快速行为,那么您最好使用其他方法之一。

于 2012-08-28T01:40:06.103 回答