代码之家  ›  专栏  ›  技术社区  ›  jxie0755

Java泛型方法不工作-参数不受限制[复制]

  •  1
  • jxie0755  · 技术社区  · 7 年前

    假设我有这个代码:

    class Demo
    {
        static <T> T pick(T a1, T a2)
        {
            return a2;
        }
    
        public static void main(String[] args)
        {
            pick("d", 123);
        }
    }
    

    据我所知,我似乎已经说明了这两个参数 a1 , a2 以及返回类型 pick 必须在同一泛型类型下 T .

    为什么编译器允许我传递 String 和一个 Integer 挑选 ?

    2 回复  |  直到 7 年前
        1
  •  5
  •   MTCoster    7 年前

    两个 String Integer 是的子类 Object 以及Java中的其他类型。在编译泛型方法(或类)时,Java试图找到泛型类型的每个实例之间共享的最接近的超类型。这部分永远不会失败,因为 对象 存在。但如果将泛型类型解析为 对象 ,它可能不再有用。

    如果编译器允许使用任何类型,那么在这里使用泛型有什么意义呢?这一切都与返回类型有关。假设你对 pick() ,当您试图编译每一行时,您认为会发生什么?

    Object o = pick("Hello", 123);       // 1
    
    String s = pick("Hello", 123);       // 2
    String s = pick("Hello", "world");   // 3
    
    Integer i = pick("Hello", 123);      // 4
    Integer i = pick(123, 456);          // 5
    int i = pick(123, 456);              // 6
    

    编译得很好,但是您丢失了任何有用的类型信息。如果你根本不使用仿制药,而只是使用 对象 为了一切。它必须在Java 5之前完成,以及大量的铸造和异常捕获。

    惯于编译:

    error: incompatible types: inferred type does not conform to upper bound(s)
    

    因为这两个论点 拾取() 只分享 对象 作为一种常见的超类型, T 变成 对象 和一个 对象 返回并且不能分配 对象 到A 整数 .

    不过效果很好。两个参数的类型相同,因此 T 很容易决定 . 因为类似的原因工作。

    还工作,但 因为 T 变成 int . int 是基元类型,因此不能在泛型中使用。尝试解析泛型类型时 T ,首先是编译器 autoboxes 实数类的原始参数( 整数 在这种情况下)。这也发生在 甚至当你简单地指定一个类似 Integer i = 123; . 不同之处在于 整数 未装箱 回到一个 int 以便它可以分配给 i .


    在您的示例实现中 拾取() ,返回值的类型应与第二个参数的类型相同。如果您的API指定结果始终主要从该参数派生,则可以使用两个泛型类型:

    static <T, U> T pick(U a1, T a2) {
        return a2;
    }
    

    加上这个, 仍然无法编译,但是 按您的预期工作。

        2
  •  2
  •   Mad Physicist    7 年前

    编译器将遍历的继承树 a1 a2 找到一个共同的祖先,在这种情况下 Object . 您没有看到的部分原因是您放弃了返回值。以下两个版本无法编译:

    String choice = pick("d", 123);
    

    Integer choice = pick("d", 123);
    

    但是,以下内容将:

    Object choice = pick("d", 123);