【问题标题】:Is there a Union in Java Generics?Java泛型中有联合吗?
【发布时间】:2009-11-08 19:08:27
【问题描述】:

我可以在一个集合中包含两种不同的类型吗?例如,我可以有 List 吗?

【问题讨论】:

  • 一个相反的问题:为什么在一个集合中有两种不同的类型?
  • @BalusC - 我遇到的这种构造的一个用例是模型对象。例如在 REST API 中,它对应于表示带有 oneOf 字段的 protobuf 消息的数据传输对象 (DTO)。 oneOf 本质上是一个联合。它可以包含许多指定的不同类型之一。任何这些类型的值都占用相同的内存,并且一次只能存储一种类型。它似乎类似于 C 中的union

标签: java generics


【解决方案1】:

不。不过,您有几个选择:

  • 您可以使用列表 并存储您喜欢的任何内容;或

  • 您可以使用列表 并将您的数据放入其中一个类成员中。

编辑:示例。

class UnionHolder {
  public String stringValue;
  public int intValue;
}

List < UnionHolder > myList 
...

当然,您需要一些额外的代码来确定要从您刚刚从列表中取出的 UnionHolder 对象中提取哪种数据。一种可能性是让第三个成员具有不同的值,具体取决于它的值,或者你可以有一个类似的成员函数

public boolean isItAString() { return (this.stringValue != null }

【讨论】:

  • 你能解释一下第二个选项吗?
【解决方案2】:

如果您正在使用 Java 8 或更高版本进行函数式编程,您可能想尝试JavaSealedUnions

Union2.Factory<String, Integer> factory = GenericUnions.doubletFactory();
Union2<String, Integer> strElem = factory.first("hello");
Union2<String, Integer> intElem = factory.second(3);
List<Union2<String, Integer>> list = Array.asList(strElem, intElem);
for (Union2<String, Integer> elem : list) {
    elem.continued(
        strElem -> System.out.println("string: " + strElem),
        intElem -> System.out.println("integer: " + intElem));
}

尚未对此进行测试,但我想你明白了。

【讨论】:

    【解决方案3】:

    简短回答?不,您可以(当然)拥有Objects 中的List,但是您可以将任何东西 放入其中,而不仅仅是StringInteger 对象。

    您可以创建一个容器对象列表,该容器对象将包含IntegerString(可能通过泛型)。有点麻烦。

    public class Contained<T> {
       T getContained();
    }
    

    并实现Contained&lt;Integer&gt;Contained&lt;String&gt;

    当然,真正的问题是你为什么要这样做?我希望一个集合包含相同类型的对象,然后我可以遍历这些对象并对其执行操作,而不必担心它们是什么。也许您的对象层次结构需要进一步考虑?

    【讨论】:

      【解决方案4】:

      除了已经提供的不错的答案...


      您的算法中可能有两种数据类型。但是您可能不必将它们放在同一个列表中...

      创建两个类型的列表可能更清楚您的算法,您仍将保持“类型安全”并携带所有数据。接下来是两个代码示例,第二个将两个列表分组到一个 MyData 对象中。

      public class Algorithm1 {
      
        public void process(List<String> strings, List<Integer> integers) {
          ...
        }
      
      }
      
      --------------------------------------
      
      public class DataPair {
      
        public List<String> strings;
        public List<Integer> integers;
      
      }
      
      public class Algorithm2 {
      
       public void process(DataPair dataPair) {
         ...
       }
      
      }
      

      【讨论】:

        【解决方案5】:

        没有。这样想:使用泛型,整个想法是提供类型安全。如果您可以将不同类型的对象放入其中,那将是不可能的。

        您可以使用非通用 java.util.List 来实现您的目的。

        如果您想确保只有 StringInteger 对象进入列表,您可以创建自己的 List 实现,如下所示:

        public class MySpecialList {
           private List list= new LinkedList();
           ...
           public void add(final String string) {
               list.add(string);
           }
        
           public void add(final Integer integer) {
               list.add(integer);
           }
           ...
           // add rest of List style methods
        }
        

        缺点:您失去了List 界面的清晰度......

        【讨论】:

        • “使用泛型,整个想法是提供类型安全。如果你可以将不同类型的对象放入其中,这是不可能的”。因为这个而被否决。联合类型也可能是类型安全的(无论是否存在此类实现)。
        【解决方案6】:

        您所描述的是Visitor pattern 的完美用例

        • 100% 静态类型检查
        • 不需要 Java 8 或更高版本

        用法:

        List<UnionType> unionTypes = Arrays
            .asList(new StringContainer("hello"), new IntegerContainer(4));
        
        for (UnionType unionType : unionTypes) {
            unionType.when(new UnionType.Cases<Integer>() {
                @Override
                public Integer is(StringContainer stringContainer) {
                    // type-specific handling code
                }
        
                @Override
                public Integer is(IntegerContainer integerContainer) {
                    // type-specific handling code
                }
            });
        }
        

        样板代码:

        interface UnionType {
            <R> R when(Cases<R> c);
            interface Cases<R> {
                R is(StringContainer stringContainer);
                R is(IntegerContainer integerContainer);
            }
        }
        
        class StringContainer implements UnionType {
        
            private final String value;
            public StringContainer(String value) { this.value = value; }
            public String getValue() { return value; }
        
            @Override
            public <R> R when(Cases<R> cases) {
                return cases.is(this);
            }
        }
        
        class IntegerContainer implements UnionType {
        
            private final Integer value;
            public IntegerContainer(Integer value) { this.value = value; }
            public Integer getValue() { return value; }
        
            @Override
            public <R> R when(Cases<R> cases) {
                return cases.is(this);
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-09-17
          • 1970-01-01
          • 2020-04-12
          • 2022-01-22
          • 1970-01-01
          • 2016-11-13
          • 2013-11-19
          • 1970-01-01
          相关资源
          最近更新 更多