【问题标题】:Any way to make a generic List where I can add a type AND a subtype?有什么方法可以制作一个通用列表,我可以在其中添加一个类型和一个子类型?
【发布时间】:2011-01-05 23:35:08
【问题描述】:

我明白为什么我不能执行以下操作:

private class Parent {
};

private class Child extends Parent {
};

private class GrandChild extends Child {
};

public void wontCompile(List<? extends Parent> genericList, Child itemToAdd) {
    genericList.add(itemToAdd);
}

我的问题是有任何实用的方法来拥有一个类型安全的列表,您可以在其中调用 add(E),其中已知 E 只是父级或子级?

我依稀记得“|”的一些用法用于通配符边界的运算符,但我在规范中找不到它...

谢谢!

【问题讨论】:

标签: java list generics add


【解决方案1】:

没有。

add(E) 中,只能在运行时确定 E 的确切类型。由于子类型关系,任何声明为 Parent 类型的变量都可以持有对 GrandChild 对象的引用;没有办法创建一个列表,您不能添加元素类型的子类型的对象(至少,这样的操作将被编译器禁止)。

真正的问题是:你为什么想要那个?也许你的继承层次是颠倒的。

【讨论】:

  • 这是一个遗留问题。 Swing API 不是通用的,需要大量子类化。因此,在我刚刚继承的代码中,对于所有原始类型和未经检查的侦听器列表、JMenuItems 等的使用,有很多 @Suppresswarnings。我希望提高此代码的类型安全性,并删除大部分 @Suppresswarnings .
  • 这并不能解释为什么您需要阻止将 GrandChild 实例添加到列表中。
【解决方案2】:

为什么不呢?您所需要的只是满足调用参数的 List 和 item 参数的匹配泛型类型,您可以非常简单地实现:

import java.util.ArrayList;
import java.util.List;

public class TestClass {

  private class Parent {
  };

  private class Child extends Parent {
  };

  private class GrandChild extends Child {
  };

  public <T extends Parent> void compilesNow(final List<T> genericList, final T itemToAdd) {
    genericList.add(itemToAdd);
  }

  public void addSomeDescendents() {
    final List<Parent> list = new ArrayList<Parent>();
    compilesNow(list, new Parent());
    compilesNow(list, new Child());
    compilesNow(list, new GrandChild());
  }
}

编辑:抱歉,我错过了关于排除 GrandChild 的内容......但是,我的示例进一步说明了如何利用泛型使这个场景至少编译

【讨论】:

    【解决方案3】:

    你的类层次结构

    public class Parent {
    
    }
    
    public class Child extends Parent {
    
    }
    
    public class GrandChild extends Child {
    
    }
    

    如何将类型及其子类型添加到泛型List

    public class Runner {
    
        //List that contains anything that has a super class Parent
        private static List<? super Parent> genericList = new ArrayList<>(); 
    
        public static void main(String[] args) {
            Parent parent = new Parent();
            Child child = new Child();
            GrandChild grandChild = new GrandChild();
    
            genericList.add(parent);
            genericList.add(child);
            genericList.add(grandChild);
    
            genericList.forEach(System.out::println);
        }
    }
    

    输出

    com.abd.test.generics.Parent@1218025c 
    com.abd.test.generics.Child@816f27d 
    com.abd.test.generics.GrandChild@87aac27
    

    【讨论】:

      【解决方案4】:

      您可以创建一个外观并在委托给封装列表之前执行您自己的 instanceof 检查。

      这会很丑陋,而且很可能是一个可怕的想法。

      【讨论】:

        猜你喜欢
        • 2021-01-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-16
        • 1970-01-01
        • 2014-07-05
        • 1970-01-01
        相关资源
        最近更新 更多