[英]How to return a list of generic type T that extends something
I have a problem with returning a list of a generic type T that extends something.我在返回一个扩展了某些东西的泛型类型 T 的列表时遇到了问题。
I have a base class, called A, and 2 subclasses, B and C.我有一个名为 A 的基础 class 和 2 个子类 B 和 C。 I want to return from a method either a list of B's or a list of C's depending on some context, but I cannot get the compiler to agree with it.
我想根据某些上下文从方法返回 B 列表或 C 列表,但我无法让编译器同意它。
What I mean is:我的意思是:
import java.util.List;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
List<B> ls1 = new Main().method1();
List<C> ls2 = new Main().method2(); // Won't work,
// have to cast to it
// i.e. List<C> ls2 = (List<C>) new Main().method2();
System.out.println(ls1);
System.out.println(ls2);
}
<T extends A> List<T> method1() {
List<B> ls = new ArrayList<>();
ls.add(new B());
return ls; // Doesn't work now, compiler error
// works if I explicitly cast to it, but says
// unsafe or unchecked operation
// return (List<T>) ls;
}
List<? extends A> method2() {
List<C> ls = new ArrayList<>();
ls.add(new C());
return ls;
}
}
class A {
}
class B extends A {
}
class C extends A {
}
As you can see, I tried both a wildcard and an actual type T, but neither of them gets rid of the compiler error: "incompatible types".如您所见,我尝试了通配符和实际类型 T,但它们都没有摆脱编译器错误:“不兼容的类型”。
Any help would be much appreciated, thank you.任何帮助将不胜感激,谢谢。
To fix compile error with修复编译错误
List<C> ls2 = new Main().method2();
You can just do你可以做
List<? extends A> ls2 = new Main().method2();
Note, that this cannot be List<C>
, it is list of something that extends A .请注意,这不能是
List<C>
,它是扩展 A 的东西的列表。 Using cast (List<C>)
is wrong here, because there is no guarantee that method2
returns list of only C, it can be, for example, a mix of C and B objects.在这里使用 cast
(List<C>)
是错误的,因为不能保证method2
返回的列表仅包含 C,例如,它可以是 C 和 B 对象的混合。
Upd: regarding method1
it is also wrong to do a cast to (List<T>) ls
for s similar reason.更新:关于
method1
,出于类似的原因,对(List<T>) ls
进行强制转换也是错误的。 Imagine you implement method1
like this想象一下你像这样实现
method1
<T extends A> List<T> method1() {
List<C> ls = new ArrayList<>();
ls.add(new C());
return (List<T> ) ls;
}
Then in your main
method you can do following and compiler won't complain然后在您的
main
方法中,您可以执行以下操作,编译器不会抱怨
List<B> ls1 = new Main().method1();
B b = ls1.get(0);
But you'll get a runtime ClassCastException
on the line B b = ls1.get(0);
但是你会在
B b = ls1.get(0);
行上得到一个运行时ClassCastException
;
It is dangerous to say a list holds items of type B
and allow an item of type C
to exist inside of it.说一个列表包含
B
类型的项目并允许C
类型的项目存在于其中是危险的。 It is safer to say that the list contains an interface or super-class instead.更安全地说,列表包含一个接口或超类。
Here is a dangerous example that throws a runtime exception.这是一个引发运行时异常的危险示例。
import java.util.*;
public class Main {
public static class A {
public String getA() { return "A"; }
@Override public String toString() { return getA(); }
};
public static class B extends A {
public String getB() { return "B"; }
@Override public String toString() { return getB(); }
}
public static class C extends A {
public String getC() { return "C"; }
@Override public String toString() { return getC(); }
}
public static void main(String[] args) {
List<B> ls1 = new Main().method3();
List<C> ls2 = new Main().method3();
// Will work, because toString() for each class is handled by each class.
System.out.println(ls1);
System.out.println(ls2);
// Runtime errors!
ls1.stream().map(B::getB).forEach(System.out::println);
ls2.stream().map(C::getC).forEach(System.out::println);
}
public static <T extends A> List<T> method3() {
return Arrays.asList((T) new A(), (T) new B(), (T) new C());
}
}
The type of your list should be a common ancestor eg List<A> ls1
so that you can safely call common methods as you iterate through the list.您的列表的类型应该是一个共同的祖先,例如
List<A> ls1
以便您在遍历列表时可以安全地调用常用方法。
public static void main(String[] args) {
List<A> ls3 = new Main().method3();
ls3.stream().map(A::toString).forEach(System.out::println);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.