【问题标题】:Can I get a collection of object extending a class and implementing an interface?我可以获得扩展类并实现接口的对象集合吗?
【发布时间】:2025-11-26 07:50:02
【问题描述】:

我的问题没有什么可补充的,基本上:

class A {}
interface I {}

// how can I get a Set<> of object of type A that implements I?

我尝试了一些东西&lt;A &amp; I&gt;&lt;A extends I&gt;&lt;? super A extends I&gt; 和其他一些东西,但没有找到任何可行的方法,所以我想知道这是否可行。如果不是,我很好奇它背后的原因。

谢谢

【问题讨论】:

  • A 和 I 是实际的类和接口名称,还是代表泛型类型参数?
  • 看起来与此处相同的问题:[基于 java 中的超类和子类的泛型类型的多重限制][1] [1]:*.com/questions/4085557/…
  • John 是对的,看起来如果不使封闭类也通用,我就无法拥有这样的集合,这很不幸:)。

标签: java


【解决方案1】:

Java 不支持交集类型,它仅在声明类型参数时支持多个边界(如extends A &amp; I)。也就是说,我们不能使用像 A &amp; I 这样的符号来表示同时扩展 A 和 I 的类型族,但是我们可以声明一个类型参数 &lt;T extends A &amp; I&gt; 来引用一个特定这样的类型.

如果后者是您想要的,那么类型参数非常适合。但是,如果您的收藏应该承认AI 的不相关子类型,那么似乎不存在好的解决方案。我最好的想法是像这样的黑客:

class AISetWrapper {
    Set<A> set = new HashSet<>();

    <T extends A & I> Set<T> getSet() {
        return (Set<T>) set; // unchecked cast that only works because generics are not reified
    }
}

这将允许我们写:

class AI1 extends A implements I { }

class AI2 extends A implements I { }

public static void main(String[] args) {
    AISetWrapper aiSet = new AISetWrapper();
    aiSet.get().add(new AI1()); // compiles
    aiSet.get().add(new AI2()); // compiles
    aiSet.get().add(new A()); // does not compile
    aiSet.get().add(new I() {}); // does not compile
}

【讨论】:

  • 似乎class AISetWrapper&lt;T extends A &amp; I&gt; 会避免未经检查的演员表。
  • 这就是我的回答所说的类型参数方法。正如我在回答中已经说过的那样,这种方法将集合的所有元素限制为扩展 A 和 I 的 特定 通用超类型。也就是说,您不能将 AI1 和 AI2 的实例添加到同一个集合.
  • 我的观点是,在hack 解决方案中,将泛型声明移动到类级别而不是方法级别将消除强制转换警告。
  • 我明白了。但这样做会改变意思,因为我的评论试图解释......
【解决方案2】:

你必须让 A 实现 I:

interface I {}
class A implements I {}

Set<A> setOfA;

也有可能

class SubA extends A implements I { }
Set <SubA> setOfSubA;

类 A 的使用不能改变它的行为,正如它突然“实现” I 所表明的那样。接口方法的实现应该从哪里来?

【讨论】:

    【解决方案3】:

    我能够做到以下几点:

    public class MyClass<T extends String & Iterable>{
        private Set<T> mySet;
    }
    

    public <T extends String & Iterable> void myFancyMethod(Set<T> mySet){}
    

    但是当我这样做时

    private Set<? extends String & Iterable>
    

    我收到Syntax error on token "&amp;" 的编译错误。似乎您可以在声明类型 &lt;T&gt; 时使用 &amp; 语法,但不适用于通配符 &lt;? ...&gt;

    可以在以下位置找到更好的讨论:Java Generics Wildcarding With Multiple Classes

    【讨论】:

      【解决方案4】:

      你可以编写自己的类:

      public class MySet<E extends A & I> extends HashSet<E> {
          // blank
      }
      

      这将简单地确保MySet 的任何实例将仅包含扩展A 并实现I 的对象。

      【讨论】:

      • 对不起,我不小心写了implements 而不是&amp;。刚刚修好了。
      • 应该是HashSet&lt;E&gt;。但是,这将 OP 限制为 Set 的单个实现。
      【解决方案5】:
      // how can I get a Set<> of object of type A that implements I?
      

      您不能在一个通用声明中同时保证两者。你可以做类似的事情

      public void addToSet(I iInstance) {
         if(iInstance instanceof A){  
         //logic to add to your set
          }
      }
      

      【讨论】:

      • 请问Set&lt;?&gt;在哪里?
      • 由于您希望您的对象同时扩展A 并实现I,您可以将它们用作泛型。
      • 但是上面没有设置传递的对象扩展 A 并实现 I 的编译时限制,只是一个或另一个。这里的重点是编译时检查,因为作为运行时你可以通过类型擦除做任何你想做的事情。
      • 问题是关于获取扩展 A 并实现 I 的对象集。它没有提到编译时间或运行时间。是的,不符合条件的对象(仅实现 I)在通过上述函数添加到集合时可能会编译,但它们实际上不会被添加,因为内部检查将失败。
      最近更新 更多