为了账号安全,请及时绑定邮箱和手机立即绑定

Java集合、泛型和抽象类:具体类信息丢失

Java集合、泛型和抽象类:具体类信息丢失

HUWWW 2021-11-11 16:38:47
我有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。


查看完整回答
反对 回复 2021-11-11
  • 1 回答
  • 0 关注
  • 192 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信