我有Bar扩展抽象类的类(可能还有许多其他类)AbstractFoo。将 的实例转换Bar为 时FooDTO,会检测到具体类。但是,在将Bar实例集合转换为 的列表时FooDTO,会丢失具体的类信息,转换是在 的基础上进行的AbstractFoo。这里出了什么问题?public class CollectionGenericsNGTest { public static abstract class AbstractFoo { } public static class Bar extends AbstractFoo { } public static class FooDTO { final boolean isBar; public FooDTO(AbstractFoo f) { this.isBar = false; } public FooDTO(Bar b) { this.isBar = true; } } public static class FooDTOList { List<FooDTO> list; public FooDTOList(Collection<? extends AbstractFoo> source) { list = source.stream() .map(entry -> new FooDTO(entry)) .collect(Collectors.toList()); } public List<FooDTO> getList() { return list; } } @Test public void testDTO() { Bar b = new Bar(); FooDTO f = new FooDTO(b); assertTrue(f.isBar); } @Test public void testDTO_abstract() { AbstractFoo b = new Bar(); FooDTO f = new FooDTO(b); assertTrue(f.isBar); // <-- fails, too } @Test public void testDTOList() { Bar b = new Bar(); List<Bar> collection = Arrays.asList(b); FooDTOList list = new FooDTOList(collection); FooDTO f = list.getList().get(0); assertTrue(f.isBar); // <--- this fails! }}
1 回答
HUX布斯
TA贡献1876条经验 获得超6个赞
这里
.map(entry -> new FooDTO(entry))
你总是打电话
new FooDTO(AbstractFoo)
设置this.isBar为 false的构造函数。
即使持有的对象entry具有运行时类型Bar,变量entry也具有类型AbstractFoo,因为它是 a 的一部分Collection<? extends AbstractFoo>,所以编译器知道该对象必须是 an AbstractFoo,但不知道它是 a Bar。重载解析适用于编译类型时的引用类型,而不是运行时对象的类型。
如果您想检查 持有的对象的运行时类型entry,而不是变量类型,您可以考虑使用
this.isBar = (f instanceof Bar);
当你分配到你的领域。这将检查引用的实际对象的运行时类型f。
在你更简单的情况下
Bar b = new Bar();
FooDTO f = new FooDTO(b);
构造函数调用被解析为,new FooDTO(Bar)因为您传递给它一个类型的引用Bar。
如果您改为:
AbstractFoo b = new Bar();
FooDTO f = new FooDTO(b);
那么构造函数调用将解析为new FooDTO(AbstractFoo),因为您将传递一个类型的引用AbtractFoo。
添加回答
举报
0/150
提交
取消