代码之家  ›  专栏  ›  技术社区  ›  Hank Jesus M C

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

  •  0
  • Hank Jesus M C  · 技术社区  · 6 年前

    Bar (可能还有许多其他类)扩展抽象类 AbstractFoo . 转换的实例时 酒吧 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 回复  |  直到 6 年前
        1
  •  3
  •   khelwood Muhammed Elsayed.radwan    6 年前

    在这里

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

    你是

    new FooDTO(AbstractFoo)
    

    设置 this.isBar

    即使物体被 entry 具有运行时类型 Bar 进入 有类型 AbstractFoo ,因为它是 Collection<? extends AbstractFoo> ,因此编译器知道对象必须是 AbstractFoo公司 ,但不知道这是一个 酒吧 . 重载解析作用于编译类型的引用类型,而不是运行时的对象类型。

    进入 ,而不是变量类型,您可以考虑使用

    this.isBar = (f instanceof Bar);
    

    当你分配到你的领域。它将检查所引用的实际对象的运行时类型 f


    在你更简单的情况下

    Bar b = new Bar();
    FooDTO f = new FooDTO(b);
    

    new FooDTO(Bar) 酒吧 .

    AbstractFoo b = new Bar();
    FooDTO f = new FooDTO(b);
    

    然后构造函数调用将解析为 new FooDTO(AbstractFoo) ,因为您将传递类型为的引用 AbtractFoo .