【问题标题】:Converting from EnumSet<A> to Set<B> when A inherits from B当 A 从 B 继承时从 EnumSet<A> 转换为 Set<B>
【发布时间】:2011-09-25 14:15:15
【问题描述】:

标题几乎解释了这个问题。我有一个接口方法:

Set<Field> getFieldSet()

我有一个类,User,看起来像这样

class User {
    enum Fields implements Field {
        USERNAME, PASSWORD;
        ...
    }
    ...
}

现在我想实现UsergetFieldSet() 方法。天真的方式似乎只是return EnumSet.allOf(Fields.class),但我收到以下错误:

> Type mismatch: cannot convert from Set<User.Fields> to Set<Field>

除了手动将 EnumSet 复制到Set&lt;Field&gt; 之外,还有什么好的方法吗?

【问题讨论】:

  • 你不能把它投给Set&lt;Field&gt;吗?
  • @Alex:不,这在 Java 中是不允许的。如果您可以这样做,那么它可能会导致问题,例如:Set&lt;Object&gt; o = new HashSet&lt;Integer&gt;(); o.add("I'm not an integer");

标签: java enums enumset


【解决方案1】:

您可以返回new HashSet&lt;Field&gt;(EnumSet.allOf(Fields.class));

这将解决您不能将 Set&lt;User.Fields&gt; 类型的值分配给 Set&lt;Field&gt; 类型的变量这一事实。

或者,您的界面可以改为Set&lt;? extends Field&gt; getFields()。您可以Set&lt;User.Field&gt; 分配给捕获变量。

【讨论】:

  • 请注意,构造一个新的 HashSet 将导致集合条目被复制,这首先​​消除了使用 EnumSet 的性能优势。
  • 是的。你的答案更好:)
  • 通常不鼓励从 API 返回通配符类型:这会增加调用 API 的类的复杂性。最好只返回Set&lt;Field&gt;
  • @Daniel:我同意。它确实使事情变得更复杂,但在某些情况下它仍然有用。我提到它只是因为它是一个可能的解决方案,具体取决于 OP 的整体设计。
  • 好点。对于 SPI 来说,让接口更加灵活,这样实现提供者可以返回他们想要的任何东西,这似乎是一个更好的主意。
【解决方案2】:

这是我认为的一个很好的解决方案。这不是你想要的,但足够接近

import java.util.EnumSet;
import java.util.Set;

public class User {
    enum Fields implements Field {
        USERNAME,
        PASSWORD;
    }

    Set< ? extends Field> getFieldSet() {
        return EnumSet.allOf(Fields.class);
    }
}

【讨论】:

    【解决方案3】:

    使用Collections.unmodifiableSet:

    return Collections.<Field>unmodifiableSet(EnumSet.allOf(Fields.class));
    

    优点:

    • 没有不安全的转换强制转换:操作在运行时是类型安全的
    • 返回的集合实际上是Set&lt;Field&gt;,而不是Set&lt;? extends Field&gt;
    • 该集合没有被复制,只是被包装
    • 返回的集合不能被改变

    缺点:

    • 返回的集合不能被改变,但这样做也不安全。

    【讨论】:

      【解决方案4】:

      这不起作用的原因是Set&lt;Fields&gt; 不是Set&lt;Field&gt; 的子类型。例如,如果您从方法中返回 Set&lt;Fields&gt;,您可能会遇到如下情况:

      Set<Field> fieldSet = user.getFieldSet(); //Returns an EnumSet<Fields>
      fieldSet.add(new Field(){}); //Would compile, but would blow up at runtime, 
                                   //because the set can only contain Fields enum 
                                   //constants
      

      您最好的选择是使用不同的集合实现(通常是不可修改的集合)来返回值。例如:

      Set<Field> getFieldSet() {
          return Collections.unmodifiableSet(EnumSet.allOf(Fields.class));
      }
      

      或者,如果您需要集合是可变的(通常可能不是一个好主意)

      Set<Field> getFieldSet() {
          return new HashSet(EnumSet.allOf(Fields.class));
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-15
        • 1970-01-01
        相关资源
        最近更新 更多