java - 使用泛型处理构造函数中的类型删除

标签 java generics constructor type-erasure

我正在尝试创建一个只能容纳两个对象之一的类,我想用泛型来实现。这是想法:

public class Union<A, B> {

    private final A a;    
    private final B b;

    public Union(A a) {
        this.a = a;
        b = null;
    }

    public Union(B b) {
        a = null;
        this.b = b;
    }

    // isA, isB, getA, getB...

}

当然这不会起作用,因为由于类型删除,构造函数具有相同的类型签名。我意识到一个解决方案是让一个构造函数接受这两个值,但我希望其中一个值是空的,因此使用单参数构造函数似乎更优雅。

// Ugly solution
public Union(A a, B b) {
    if (!(a == null ^ b == null)) {
        throw new IllegalArgumentException("One must exist, one must be null!");
    }
    this.a = a;
    this.b = b;
}

对此有优雅的解决方案吗?


Edit 1: I am using Java 6.

Edit 2: The reason I want to make this is because I have a method that can return one of two types. I made a concrete version with no generics but was wondering if I could make it generic. Yes, I realize that having a method with two different return types is the real issue at hand, but I was still curious if there was a good way to do this.

I think durron597's answer is best because it points out that Union<Foo, Bar> and Union<Bar, Foo> should act the same but they don't (which is the main reason why I decided to stop pursuing this). This is a much uglier issue than the "ugly" constructor.

For what it's worth I think the best option is probably make this abstract (because interfaces can't dictate visibility) and make the isA and getA stuff protected, and then in the implementing class have better named methods to avoid the <A, B> != <B, A> issue. I will add my own answer with more details.

Final edit: For what it's worth, I decided that using static methods as pseudo constructors (public static Union<A, B> fromA(A a) and public static Union<A, B> fromB(B b)) is the best approach (along with making the real constructor private). Union<A, B> and Union<B, A> would never realistically be compared to each other when it's just being used as a return value.

Another edit, 6 months out: I really can't believe how naive I was when I asked this, static factory methods are so obviously the absolute correct choice and clearly a no-brainer.

All that aside I have found Functional Java to be very intriguing. I haven't used it yet but I did find this Either when googling 'java disjunct union', it's exactly what I was looking for. The downside though it that Functional Java is only for Java 7 and 8, but luckily the project I am now working on used Java 8.

最佳答案

这样做真的没有任何意义。这什么时候有意义?例如(假设,目前,您的初始代码有效):

Union<String, Integer> union = new Union("Hello");
// stuff
if (union.isA()) { ...

但如果你这样做了,相反:

Union<Integer, String> union = new Union("Hello");
// stuff
if (union.isA()) { ...

这会有不同的行为,即使类和数据是相同的。你的概念isAisB基本上是“左对右”——哪个是左对右比哪个是字符串对哪个是整数更重要。换句话说,Union<String, Integer>Union<Integer, String> 非常不同,这可能不是您想要的。

例如,考虑一下如果我们说:

List<Union<?, ?>> myList;
for(Union<?, ?> element : myList) {
  if(element.isA()) {
    // What does this even mean? 

某物是 A 的事实没关系,除非你关心它是左派还是右派,在这种情况下你应该这样调用它。


如果此讨论不是关于左与右,那么唯一重要的是在创建类时使用您的特定类型。简单地拥有一个界面会更有意义;

public interface Union<A, B> {
  boolean isA();
  boolean isB();
  A getA();
  B getB();
}

您甚至可以在抽象类中使用“is”方法:

public abstract class AbstractUnion<A, B> {
  public boolean isA() { return getB() == null; }
  public boolean isB() { return getA() == null; }
}

然后,当您实际实例化该类时,无论如何您都会使用特定类型...

public UnionImpl extends AbstractUnion<String, Integer> {
  private String strValue;
  private int intValue

  public UnionImpl(String str) {
    this.strValue = str;
    this.intValue = null;
  }

  // etc.
}

然后,当您真正选择了实现类型时,您就会真正知道自己得到了什么。


旁白:如果在阅读以上所有内容后,您仍然想按照最初问题中描述的方式执行此操作,那么正确的方法是使用带有私有(private)构造函数的静态工厂方法,如所述@JoseAntoniaDuraOlmos's answer here .但是,我希望您进一步考虑在实际用例中您实际需要您的类做什么。

关于java - 使用泛型处理构造函数中的类型删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31880691/

相关文章:

java - 如何使用 Selenium 和 Java 在 webtable 单元格内发送文本

Java SceneBuilder设计单面板

c# - 结果是类型的交集?

java - 如何限制泛型类型不扩展类?

java - 允许多种预定义类型的集合

ecmascript-6 - 在类字段初始化后,以正常的方式运行 'constructor' 或函数吗?

Java构造函数重载歧义

java - 斐波那契递归不适用于 Java

java - 如何使用 struts2 将 Java bean 数组呈现为 XML?

Java - 具有相同参数的多个构造函数