Java集合、泛型和抽象类: concrete class information lost

标签 java generics abstract

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

}

最佳答案

这里

.map(entry -> new FooDTO(entry))

总是打电话

new FooDTO(AbstractFoo)

设置 this.isBar 的构造函数为假。

即使entry持有的对象运行时类型 Bar ,变量entry类型为AbstractFoo ,因为它是 Collection<? extends AbstractFoo> 的一部分,因此编译器知道该对象必须是 AbstractFoo ,但不知道它是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 类型的引用.

关于Java集合、泛型和抽象类: concrete class information lost,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52758643/

相关文章:

java - 为泛型类型调用重载方法 'equals'

java - 如何迭代双链表并创建一个具有特定值的新列表?

methods - 抽象方法未指定主体 - 尝试实现 super 接口(interface)方法的接口(interface)在 JDK 8 中给出编译时错误

Java调用抽象父类(super class)中后代类的方法

java - 如何使用荣格定义边或顶点的属性?

java - 从 JSON 对象中获取第一个键和值

C# 无限泛型类型作为约束

c++ - C++ 抽象类的问题(我可以在 Java 中完成,但不能在 C++ 中完成!)

java - 在 Java 中实现单例模式

java - 使用set Object()代替jdbc中的所有数据类型