【问题标题】:Unusual generic syntax: Arrays.<String>asList(...)不寻常的通用语法:Arrays.<String>asList(...)
【发布时间】:2011-06-17 07:25:26
【问题描述】:

我发现了一个“不寻常”的通用语法,例如:

Arrays.<String>asList(...);
Collections.<String>emptyList();

显然,方法的结果是通用的。这种语法是用于类型检查的吗? Object 数组不能作为 Arrays.&lt;String&gt;asList(...) 的参数。

【问题讨论】:

    标签: java generics


    【解决方案1】:

    &lt;typearg&gt;methodname 是显式指定泛型方法的类型参数的语法

    当您使用泛型类时,通常必须指定类型参数(例如String):

    ArrayList<String> list =  new ArrayList<String>();
    

    使用泛型方法,您通常不会传递类型参数:

    public static <T> void foo(T param) {   }
    ...
    String s = ...;
    MyClass.foo(s);
    

    您会注意到我们没有在代码中明确指定我们想要fooString 版本,即没有像我们在使用泛型类时看到的那样指定明确的类型参数&lt;String&gt; (@987654331 @)。

    编译器正在使用一些编译器魔法来根据上下文推断泛型类型参数。这是一件很棒的事情,而且非常强大。

    但是,有时编译器无法自动推断类型参数:

    public static <T> void bar() { T myLocalVar = ...; ...  }
    MyClass.bar();
    

    我们试图调用bar 的具体版本,即这个调用的类型参数是什么?好吧,编译器也没有。我们必须显式声明类型参数,就像我们通常在使用泛型类时所做的那样:

    MyClass.<String>bar();
    

    另见:


    除此之外: 值得一提的是,Java 7 将添加所谓的菱形运算符,以便我们现在也可以让编译器在使用泛型类时推断类型参数:

    ArrayList<String> list =  new ArrayList<String>();
    

    变成

    ArrayList<String> list =  new ArrayList<>();
    

    What is the point of the diamond operator (<>) in Java 7?

    【讨论】:

      【解决方案2】:

      这是您显式指定泛型方法的类型参数的方式。在大多数情况下,编译器可以推断出来,但有时需要明确说明。

      【讨论】:

      • 出于我自己的好奇心 - 是否需要明确说明,因为这些方法是静态的?
      • @Christopher:没有。它适用于静态和非静态方法。
      • 需要明确说明,因为它是静态的,所以没有固定泛型类型参数的构造函数,并且无法从参数列表中推断出泛型类型参数。
      • @Christopher:非静态方法很少(如果有的话)有自己的类型参数。如果有,也会出现同样的问题。
      • @Christopher McCann 对类型的推断(还没有发生)。 (有泛型构造函数之类的东西,但实际上不记得在野外见过。)在JDK7中,您应该可以使用菱形运算符(&lt;&gt;)编写new ArrayList&lt;&gt;(),然后推理将魔法发生。
      【解决方案3】:

      上面的答案几乎可以解决您的问题,但是如果您想要一个 Java 泛型类型推断失败的具体示例并以这种方式明确说明它可以节省时间,请考虑以下类定义:

      public class A { }
      public class B extends A { }
      public class C extends A { }
      

      那么下面的代码就可以正常工作了(即Java的类型推断成功):

      List<Class<? extends A>> list = ImmutableList.of(B.class, C.class);
      

      但是对于以下情况,编译失败:

      List<Class<? extends A>> list = ImmutableList.of(B.class);
      

      没错;奇怪的是,通过删除一个参数,我们混淆了类型推断系统,因为B.classC.class的“最近共同后代”是A.class,但对于B.class本身,它只是B.class,它(由于Java 泛型中缺乏协方差)与List&lt;Class&lt;? extends A&gt;&gt; 不匹配。在这种情况下,您别无选择,只能使用:

      List<Class<? extends A>> list = ImmutableList.<Class<? extends A>>of(B.class);
      

      因为B 确实扩展了A,所以编译(和运行)就好了。

      我希望这个演示能够强调操作符的实用性。

      【讨论】:

        【解决方案4】:

        另外,Java 7 之后的编译器支持类型推断。考虑以下类定义:

        public class A { }
        public class B extends A { }
        public class C extends A { }
        

        以下所有情况均有效:

        List<Class<? extends A>> list0 = Arrays.asList(B.class, C.class);
        List<Class<? extends A>> list1 = Arrays.asList(B.class);
        
        List<A> list2 = Arrays.asList(new B());
        List<A> list3 = Arrays.asList(new B(), new C());
        
        
        List<? extends A> list4 = Arrays.asList(new B(), new C());
        List<? extends A> list5 = Arrays.asList(new B());
        

        【讨论】:

          猜你喜欢
          • 2017-09-06
          • 1970-01-01
          • 2018-12-08
          • 1970-01-01
          • 2011-10-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多