例如,假设你有两个类:
public class TestA {}
public class TestB extends TestA{}
我有一个返回List<TestB>的方法,我想将该列表中的所有对象强制转换为TestB,以便最终得到List<TestB>。
例如,假设你有两个类:
public class TestA {}
public class TestB extends TestA{}
我有一个返回List<TestB>的方法,我想将该列表中的所有对象强制转换为TestB,以便最终得到List<TestB>。
当前回答
问题是,如果您的方法包含TestB,那么它不会返回一个teststa列表,那么如果它是正确键入的呢?然后是这个铸件:
class TestA{};
class TestB extends TestA{};
List<? extends TestA> listA;
List<TestB> listB = (List<TestB>) listA;
可以像您所希望的那样工作(Eclipse会警告您进行未检查的强制转换,这正是您正在做的事情,所以meh)。那么你能用这个来解决你的问题吗?事实上你可以这样做,因为:
List<TestA> badlist = null; // Actually contains TestBs, as specified
List<? extends TestA> talist = badlist; // Umm, works
List<TextB> tblist = (List<TestB>)talist; // TADA!
这正是你想要的,对吧?或者更确切地说:
List<TestB> tblist = (List<TestB>)(List<? extends TestA>) badlist;
对我来说似乎编纂得很好。
其他回答
您可以在Eclipse Collections中使用selectInstances方法。这将涉及创建一个新的集合,但不会像使用强制转换的公认解决方案那样有效。
List<CharSequence> parent =
Arrays.asList("1","2","3", new StringBuffer("4"));
List<String> strings =
Lists.adapt(parent).selectInstancesOf(String.class);
Assert.assertEquals(Arrays.asList("1","2","3"), strings);
我在示例中加入StringBuffer是为了说明selectInstances不仅向下转换类型,而且还将过滤集合是否包含混合类型。
注意:我是Eclipse Collections的提交者。
class MyClass {
String field;
MyClass(String field) {
this.field = field;
}
}
@Test
public void testTypeCast() {
List<Object> objectList = Arrays.asList(new MyClass("1"), new MyClass("2"));
Class<MyClass> clazz = MyClass.class;
List<MyClass> myClassList = objectList.stream()
.map(clazz::cast)
.collect(Collectors.toList());
assertEquals(objectList.size(), myClassList.size());
assertEquals(objectList, myClassList);
}
这个测试演示了如何将List<Object>转换为List<MyClass>。但是需要注意的是,objectList必须包含与MyClass相同类型的实例。当List<T>使用时,可以考虑这个例子。为此,在构造函数中获取字段Class<T> clazz,并使用它来代替MyClass.class。
更新
实际上,在强类型Java AFAIK中,你不能从超类型转换为子类型。但是可以引入超类型实现的接口。
interface ITest {
}
class TestA implements ITest {
}
class TestB extends TestA {
}
public class Main {
public static void main(String[] args) {
List<ITest> testAList = Arrays.asList(new TestA(), new TestA());
Class<ITest> clazz = ITest.class;
List<ITest> testBList = testAList.stream()
.map(clazz::cast)
.collect(Collectors.toList());
System.out.println(testBList.size());
System.out.println(testAList);
}
}
或者可以从子类型转换为超类型。是这样的:
class TestA {
}
class TestB extends TestA {
}
public class Main {
public static void main(String[] args) {
var a = new TestA();
var b = new TestB();
System.out.println(((TestA) b));
List<TestB> testBList = Arrays.asList(new TestB(), new TestB());
Class<TestA> clazz = TestA.class;
List<TestA> testAList = testBList.stream()
.map(clazz::cast)
.collect(Collectors.toList());
System.out.println(testAList.size());
System.out.println(testAList);
}
}
供参考,我最初的答案指出了与泛型一起使用它的可能性。事实上,我从Hibernate DAO代码中获取了它。
你真的不能*:
示例取自本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")来抑制它。
不过我认为你选错方向了……如果该方法返回一个TestA对象列表,那么将它们强制转换到TestB确实是不安全的。
基本上,您是在要求编译器允许您在不支持TestA类型的TestB上执行操作。
很奇怪,手动强制转换列表仍然没有提供一些实现如下功能的工具箱:
@SuppressWarnings({ "unchecked", "rawtypes" })
public static <T extends E, E> List<T> cast(List<E> list) {
return (List) list;
}
当然,这不会逐个检查项,但如果我们清楚地知道我们的实现只提供子类型,那么这正是我们在这里要避免的。