【问题标题】:Why does this generic java method accept two objects of different type?为什么这个泛型 java 方法接受两个不同类型的对象?
【发布时间】:2012-12-06 04:12:39
【问题描述】:

此方法将获取两个相同类型的对象并随机返回其中一个对象:

public static <T> T random(T o1, T o2)
{
   return Math.random() < 0.5 ? o1 : o2;
}

现在,为什么编译器会接受两个不同类型的参数?

random("string1", new Integer(10)); // Compiles without errors

编辑: 现在我知道这两个参数都被隐式向上转换了,我想知道为什么编译器确实在调用以下方法时会抱怨:

public static <T> List<T> randomList(List<T> l1, List<T> l2) {
        return Math.random() < 0.5 ? l1 : l2;
    }

呼叫:

randomList(new ArrayList<String>(), new ArrayList<Integer>()); // Does not Compile

如果这些 ArrayList 参数也被向上转换为 Object,为什么这次它会给我一个错误?

【问题讨论】:

  • 因为他们都是Objects。
  • @user1914126.. 就目前而言,您的代码不应编译。您在Integer(10) 之前缺少new。
  • 是的,如果你想让编译器抱怨你必须告诉它当你调用方法时 T 应该是什么,例如MyClass.&lt;String&gt;random("string1", new Integer(10));。那将是一个错误。

标签: java generics methods parameters


【解决方案1】:

T 被推断为Object,并且两个参数都被隐式向上转换。

因此代码等价于:

Main.<Object>random((Object)"string1", (Object)new Integer(10));

可能更令人惊讶的是以下编译:

random("string1", 10);

第二个参数被自动装箱为Integer,然后两个参数都被向上转换为Object。

【讨论】:

  • 在我的脑海中,Serializable 和 Comparable 也是如此。等等,Comparable&lt;?&gt;,呃,Comparable&lt;? extends Comparable&lt;?&gt; &amp; Serializable&gt;,哦&lt;Comparable&lt;? extends Comparable&lt;哦,我放弃了。将它分配给一些愚蠢的东西并查看编译器错误消息。
  • @TomHawtin-tackline:你说得很对,尽管我还没有完全弄清楚如何在不掩盖重点的情况下将这些细节融入答案。
【解决方案2】:

T被推断为String和Integer的共同超类型,即

Object & Serializable & Comparable<? extends Object & Serializable & Comparable<? extends ... ...

好吧,没有人需要关心这个。

您可以对参数类型添加更多约束

public static <T1,T2 extends T1> T1 random(T1 o1, T2 o2)

在您的列表示例中,您需要通配符来获得类似的效果

public static <T> List<? extends T> randomList(
                                    List<? extends T> l1, List<? extends T> l2)

【讨论】:

    【解决方案3】:

    知道我知道这两个参数都被隐式向上转换, 我想知道为什么编译器在调用以下命令时会抱怨 方法:

    因为即使A 是B 的子类型,如果A 和B 不同,List&lt;A&gt; 也不是List&lt;B&gt; 的子类型。

    【讨论】:

      【解决方案4】:

      因为您没有以安全、通用的方式调用它。试试

      MyClass.<String>random("string1", new Integer(10));
      

      你会得到一个编译错误。

      或者让编译器推断类型,你也应该得到一个编译错误:

      String s = random("string1", new Integer(10));
      

      【讨论】:

      • 您无需指定方法的类型即可获得通用行为。 Integer x = random(1, 2) 也是有效的。
      • 是的,我仍在编辑我的答案以添加关于类型推断的注释。
      • @JanDvorak 或者如果有void foo(String s1, String s2),那么foo(random(....))。关键是调用本身不足以将T 绑定到String。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-26
      • 1970-01-01
      • 2019-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多