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
How do you cast a List of supertypes to a List of subtypes?
提问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 TestB
so that I end up with a List<TestB>
.
我有一个返回 a 的方法,List<TestA>
我想将该列表中的所有对象强制转换TestB
为List<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 A
and B
such that B extends A
.
Then the following code is correct:
假设有两种类型A
,B
这样B extends A
。那么下面的代码是正确的:
B b = new B();
A a = b;
The previous code is valid because B
is 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 TestA
objects, then it really isn't safe to cast them to TestB
.
我认为你在错误的方向上进行转换……如果该方法返回一个TestA
对象列表,那么将它们转换为TestB
.
Basically you are asking the compiler to let you perform TestB
operations on a type TestA
that does not support them.
基本上,您是在要求编译器让您TestB
对TestA
不支持它们的类型执行操作。
回答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 TestB
is 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 TestA
reference 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 TestA
to 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 AbstractList
and cast items in implementation. I created ListUtil
helper 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 cast
method to blindly cast objects in list and convert
method 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
}