【问题标题】:Multiple wildcard bounds多个通配符界限
【发布时间】:2012-09-02 12:28:51
【问题描述】:

假设我有以下课程:

public class Either<A, B> {
    public Object get();
}

Either 是一种存储类型 A 或 B 的一个对象的类型。get() 检索该对象。

问题是是否可以使用泛型来更改get() 的方法签名,以便返回的类型不仅仅是Object,而是A 和B 的任何常见超类型。例如,@ 987654326@可以有get()返回NumberEither&lt;Deque&lt;T&gt;, Set&lt;T&gt;&gt;可以有get()返回Iterable&lt;T&gt;Collection&lt;T&gt;,以此类推。 (显然,Either&lt;Foo,Foo&gt; 应该有 get() 返回 Foo)。

如果这是可能的话,如果我有Either&lt;List&lt;A&gt;, List&lt;B&gt;&gt;get() 可以返回的最具体的类型是什么?是原始的List、通配符List&lt;?&gt;,还是完全其他的?

【问题讨论】:

  • 真的有人回答过关于Either&lt;List&lt;A&gt;, List&lt;B&gt;&gt; 的问题吗?无论如何,它需要是List&lt;?&gt;

标签: java generics bounded-wildcard


【解决方案1】:

Java 推理确实有类似的东西,我们可以做

public static <C, A extends C, B extends C> C get(Either<A,B> e)
{   return (C)e.get();    }

inference:

    A=Integer, B=Long    ==>    C=Number

    A=List<Integer>, B=List<Long>      ==>   C=List<? extends Number>

usage:

    Either<Integer, Long> x = ...;
    get(x); // the return type is Number

但是,可能没有办法将其转换为实例方法。我们需要写

public class Either<A,B>

    public <C super A|B> C get() { ... }

or simply

    public A|B get(){ ... }

Java 不支持

【讨论】:

    【解决方案2】:

    为什么不定义一个抽象类 C,包含你认为必要的 A 和 B 的共同逻辑,并在你的 Either 类中引用它:

    public class Either<C> {
        public C get();
    }
    

    这似乎不是一个很好的答案,但是由于 Java 在编译时无论如何都会删除您的类型信息(也就是说,您的编译代码只看到 Object 而不是 AB) ,那么您最适合定义应在显式公共类中保留的内容。

    【讨论】:

    • A和B可能是不相关的类,我不能修改,比如上面的IntegerLong;可能无法抽象为公共超类。
    • 您可以包装这些类,就像 Hadoop 框架对 IntWritable 等所做的那样。包装器可以派生自一个通用的抽象类。
    【解决方案3】:

    据我所知,这是不可能的:您的Either&lt;A,B&gt; 类对通用的第三种类型(我们称之为C)进行了假设,A 和 B 都会扩展它:虽然可以编写像public class Either&lt;A extends MyNonFinalClass, B extends MyNonFinalClass&gt; {} 这样的东西,Java 不允许前向引用泛型类型,所以你甚至不能写像Either&lt;A extends C, B extends C, C&gt; 这样的东西。显然很遗憾,因为您的 Either 课程真的很方便 :)

    【讨论】:

    • 显然 javac 7 允许前向引用,所以 &lt;A,B,C&gt; 也可以。 (JLS 从未禁止前向引用)
    • 它肯定会起作用,但会破坏目的,因为您必须将自己标识为常见的超类型。也就是说,您可以使用泛型和自省的组合来推断超类型并提供相同的功能。
    【解决方案4】:

    您需要确保 A 和 B 有共同的祖先。

    public class Either<A extends CommonAncestor, B extends CommonAncestor> {
        public CommonAncestor get() {....}
    }
    

    public class Either<C, A extends C, B extends C> {
        public C get() {....}
    }
    

    【讨论】:

    • 你的观点是有效的,我认为C 是一个接口或类,但这个例子的含义不清楚:P
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-18
    • 2021-01-23
    • 1970-01-01
    • 2015-04-23
    • 2019-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多