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

我有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!

    }


}


HUWWW
浏览 199回答 1
1回答

HUX布斯

这里.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。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java