例如,假设你有两个类:

public class TestA {}
public class TestB extends TestA{}

我有一个返回List<TestB>的方法,我想将该列表中的所有对象强制转换为TestB,以便最终得到List<TestB>。


当前回答

最安全的方法是实现AbstractList并在实现中强制转换项。我创建了ListUtil helper类:

public class ListUtil
{
    public static <TCastTo, TCastFrom extends TCastTo> List<TCastTo> convert(final List<TCastFrom> list)
    {
        return new AbstractList<TCastTo>() {
            @Override
            public TCastTo get(int i)
            {
                return list.get(i);
            }

            @Override
            public int size()
            {
                return list.size();
            }
        };
    }

    public static <TCastTo, TCastFrom> List<TCastTo> cast(final List<TCastFrom> list)
    {
        return new AbstractList<TCastTo>() {
            @Override
            public TCastTo get(int i)
            {
                return (TCastTo)list.get(i);
            }

            @Override
            public int size()
            {
                return list.size();
            }
        };
    }
}

您可以使用cast方法盲目地转换列表中的对象,并使用convert方法进行安全转换。 例子:

void test(List<TestA> listA, List<TestB> listB)
{
    List<TestB> castedB = ListUtil.cast(listA); // all items are blindly casted
    List<TestB> convertedB = ListUtil.<TestB, TestA>convert(listA); // wrong cause TestA does not extend TestB
    List<TestA> convertedA = ListUtil.<TestA, TestB>convert(listB); // OK all items are safely casted
}

其他回答

由于类型擦除,这是可能的。你会发现

List<TestA> x = new ArrayList<TestA>();
List<TestB> y = new ArrayList<TestB>();
x.getClass().equals(y.getClass()); // true

在内部,两个列表的类型都是List<Object>。出于这个原因,你不能将一个转换为另一个——没有什么可以转换的。

泛型的强制转换是不可能的,但是如果你以另一种方式定义列表,则可以将TestB存储在其中:

List<? extends TestA> myList = new ArrayList<TestA>();

在使用列表中的对象时,仍然需要进行类型检查。

很奇怪,手动强制转换列表仍然没有提供一些实现如下功能的工具箱:

@SuppressWarnings({ "unchecked", "rawtypes" })
public static <T extends E, E> List<T> cast(List<E> list) {
    return (List) list;
}

当然,这不会逐个检查项,但如果我们清楚地知道我们的实现只提供子类型,那么这正是我们在这里要避免的。

简单的答案

你不能直接类型转换。

解决方案

 public <T> List<T> getSubItemList(List<IAdapterImage> superList, Class<T> clazz) {
        return superList.stream()
                .map(item -> clazz.isInstance(item) ? clazz.cast(item) : null)
                .collect(Collectors.toList());
    }

使用

private final List<IAdapterImage> myList = new ArrayList<>();

List<SubType> subTypeList = getSubItemList(myList,SubType.class);

所以这是一个简单的工作,我用来转换我的列表与超级类型到列表与子类型。我们使用的是java 8中引入的流api,在我们的超列表上使用map,我们只是检查传递的参数是否是我们的超类型的实例,返回项目。最后,我们收集成一个新的列表。当然,我们需要把result放到一个新的列表中。

你真的不能*:

示例取自本Java教程

假设有两种类型A和B,使得B扩展了A。 那么下面的代码是正确的:

    B b = new B();
    A a = b;

前面的代码是有效的,因为B是a的子类。 现在,List<A>和List<B>会发生什么?

原来List<B>不是List< a >的子类,因此我们不能写

    List<B> b = new ArrayList<>();
    List<A> a = b; // error, List<B> is not of type List<A>

此外,我们甚至不会写字

    List<B> b = new ArrayList<>();
    List<A> a = (List<A>)b; // error, List<B> is not of type List<A>

*:为了使casting成为可能,我们需要一个共同的父List< a >和List<B>: List<?例如>。以下是有效的:

    List<B> b = new ArrayList<>();
    List<?> t = (List<B>)b;
    List<A> a = (List<A>)t;

但是,您将得到一个警告。你可以通过在你的方法中添加@SuppressWarnings("unchecked")来抑制它。