Java 如何将超类型列表转换为子类型列表?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/933447/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 21:15:41  来源:igfitidea点击:

How do you cast a List of supertypes to a List of subtypes?

javalistgenericscollectionscasting

提问by Jeremy Logan

For example, lets say you have two classes:

例如,假设您有两个类:

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

I have a method that returns a List<TestA>and I would like to cast all the objects in that list to TestBso that I end up with a List<TestB>.

我有一个返回 a 的方法,List<TestA>我想将该列表中的所有对象强制转换TestBList<TestB>.

采纳答案by newacct

Simply casting to List<TestB>almost works; but it doesn't work because you can't cast a generic type of one parameter to another. However, you can cast through an intermediate wildcard type and it will be allowed (since you can cast to and from wildcard types, just with an unchecked warning):

简单地投射到List<TestB>几乎可以工作;但它不起作用,因为您不能将一个参数的泛型类型转换为另一个参数。但是,您可以通过中间通配符类型进行强制转换,并且它是允许的(因为您可以在通配符类型之间进行转换,只是带有未经检查的警告):

List<TestB> variable = (List<TestB>)(List<?>) collectionOfListA;

回答by Steve Kuo

You really can't*:

你真的不能*:

Example is taken from this Java tutorial

示例取自此 Java 教程

Assume there are two types Aand Bsuch that B extends A. Then the following code is correct:

假设有两种类型AB这样B extends A。那么下面的代码是正确的:

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

The previous code is valid because Bis a subclass of A. Now, what happens with List<A>and List<B>?

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

It turns out that List<B>is not a subclass of List<A>therefore we cannotwrite

事实证明这List<B>不是的子类,List<A>因此我们不能

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

Furthermore, we can'teven write

此外,我们甚至不能

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

*: To make the casting possible we need a common parent for both List<A>and List<B>: List<?>for example. The following isvalid:

*:例如,为了使转换成为可能,我们需要一个List<A>List<B>:的共同父级List<?>。以下内容有效:

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

You will, however, get a warning. You can suppress it by adding @SuppressWarnings("unchecked")to your method.

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

回答by jerryjvl

I think you are casting in the wrong direction though... if the method returns a list of TestAobjects, then it really isn't safe to cast them to TestB.

我认为你在错误的方向上进行转换……如果该方法返回一个TestA对象列表,那么将它们转换为TestB.

Basically you are asking the compiler to let you perform TestBoperations on a type TestAthat does not support them.

基本上,您是在要求编译器让您TestBTestA不支持它们的类型执行操作。

回答by n3rd

This is possible due to type erasure. You will find that

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

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

Internally both lists are of type List<Object>. For that reason you can't cast one to the other - there is nothing to cast.

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

回答by cd1

if you have an object of the class TestA, you can't cast it to TestB. every TestBis a TestA, but not the other way.

如果您有类的对象TestA,则无法将其强制转换为TestB. 每个TestB都是一个TestA,但不是相反。

in the following code:

在以下代码中:

TestA a = new TestA();
TestB b = (TestB) a;

the second line would throw a ClassCastException.

第二行会抛出一个ClassCastException.

you can only cast a TestAreference if the object itself is TestB. for example:

你只能投一个TestA参考,如果对象本身TestB。例如:

TestA a = new TestB();
TestB b = (TestB) a;

so, you may not always cast a list of TestAto a list of TestB.

因此,您可能并不总是将TestA列表转换为TestB.

回答by martinatime

You cannot cast List<TestB>to List<TestA>as Steve Kuo mentions BUT you can dump the contents of List<TestA>into List<TestB>. Try the following:

你可以不投List<TestB>List<TestA>史蒂夫·郭提及,但你可以转储的内容List<TestA>List<TestB>。请尝试以下操作:

List<TestA> result = new List<TestA>();
List<TestB> data = new List<TestB>();
result.addAll(data);

I've not tried this code so there are probably mistakes but the idea is that it should iterate through the data object adding the elements (TestB objects) into the List. I hope that works for you.

我没有尝试过这段代码,所以可能有错误,但想法是它应该遍历数据对象,将元素(TestB 对象)添加到列表中。我希望这对你有用。

回答by Peter Lawrey

When you cast an object reference you are just casting the type of the reference, not the type of the object. casting won't change the actual type of the object.

当您转换对象引用时,您只是在转换引用的类型,而不是对象的类型。强制转换不会改变对象的实际类型。

Java doesn't have implicit rules for converting Object types. (Unlike primitives)

Java 没有转换 Object 类型的隐式规则。(与原语不同)

Instead you need to provide how to convert one type to another and call it manually.

相反,您需要提供如何将一种类型转换为另一种类型并手动调用它。

public class TestA {}
public class TestB extends TestA{ 
    TestB(TestA testA) {
        // build a TestB from a TestA
    }
}

List<TestA> result = .... 
List<TestB> data = new List<TestB>();
for(TestA testA : result) {
   data.add(new TestB(testA));
}

This is more verbose than in a language with direct support, but it works and you shouldn't need to do this very often.

这比直接支持的语言更冗长,但它有效,您不应该经常这样做。

回答by Salandur

casting of generics is not possible, but if you define the list in another way it is possible to store TestB in it:

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

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

You still have type checking to do when you are using the objects in the list.

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

回答by Peter Heusch

The only way I know is by copying:

我知道的唯一方法是复制:

List<TestB> list = new ArrayList<TestB> (
    Arrays.asList (
        testAList.toArray(new TestB[0])
    )
);

回答by Igor Zubchenok

The best safe way is to implement an AbstractListand cast items in implementation. I created ListUtilhelper class:

最好的安全方法是在 implementation 中实现 anAbstractList和 cast items。我创建了ListUtil帮助类:

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();
            }
        };
    }
}

You can use castmethod to blindly cast objects in list and convertmethod for safe casting. Example:

您可以使用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
}