【问题标题】:What is the purpose of type arguments in constructor call following new?在 new 之后的构造函数调用中类型参数的目的是什么?
【发布时间】:2013-09-08 21:35:28
【问题描述】:

在 Java 规范 (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.9) 中,new 具有以下形式:

ClassInstanceCreationExpression ::=
| new TypeArguments_opt TypeDeclSpecifier TypeArgumentsOrDiamond_opt
    ( ArgumentListopt ) ClassBodyopt
| Primary . new TypeArguments_opt Identifier TypeArgumentsOrDiamond_opt
    ( ArgumentListopt ) ClassBodyopt

new 之后的第一个可选类型参数列表的目的是什么?我在阅读第 15.9 节时无法找到它(所有对类型参数列表的引用似乎都引用了类型/标识符之后的列表)。在标准 Java 编译器上测试随机位会产生令人困惑的结果:

public class Foo<T> { }
// ...
Foo<Integer> t1 = new <Integer> Foo<Integer>();  // works
Foo<Integer> t2 = new <Integer> Foo();           // works -- unchecked warning missing the type arg after Foo
Foo<Integer> t3 = new <Boolean> Foo<Integer>();  // works
Foo<Integer> t4 = new <Float, Boolean> Foo<Integer>();  // works
Foo<Integer> t5 = new <NotDefined> Foo<Integer>();  // fails -- NotDefined is undefined

在这些简单的例子中,第一个参数列表似乎没有做任何有意义的事情,尽管它会解析并检查其参数的有效性。

【问题讨论】:

    标签: java


    【解决方案1】:

    构造函数也可以声明类型参数

    public class Main {     
        public static class Foo<T> {
            public <E> Foo(T object, E object2) {
    
            }
        }
        public static void main(String[] args) throws Exception {
            Foo<Integer> foo = new <String> Foo<Integer>(1, "hello");           
        }    
    }
    

    这就是构造函数调用之前的&lt;String&gt; 的用途。它是构造函数的类型参数。

    以下

    Foo<Integer> foo = new <String> Foo<Integer>(1, new Object());
    

    失败

    类型的参数化构造函数 Foo(Integer, String) Main.Foo 不适用于参数(整数, 对象)

    在你的最后

    Foo<Integer> t5 = new <NotDefined> Foo<Integer>();  // fails -- NotDefined is undefined
    

    NotDefined 不是在编译期间发现的类型。如果是,它只会给你一个警告,告诉你它是unused

    【讨论】:

    • 优秀。那讲得通。仍然令人困惑的是,您可以为未指定任何类型参数的构造函数调用提供类型参数。那里有什么规则?
    • Eclipse 编译器只是警告Unused type arguments for the non generic constructor。与具有类型参数的方法类似,如果可以从参数的类型推断出&lt;...&gt;,则不必指定它。
    • 啊。有趣的。 javac 没有给出任何警告(即使 -Xlint:warnings 开启),这可能是我困惑的根源。我觉得很奇怪你可以像这样“过度指定”类型参数(即提供构造函数不使用的类型参数)。无论如何,它就是这样,我猜。谢谢! (我认为Java允许这样做的原因与泛型类型擦除有关。如果其他人可以填写详细信息,那就太好了!)
    【解决方案2】:

    您可以为方法调用添加无用的类型参数,例如

    Math.<Runnable>max(1,2);
    
    System.out.<Button>println();
    

    http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.1-200-E

    非泛型方法可能适用于提供显式类型参数的调用。事实上,它可能会被证明是适用的。在这种情况下,类型参数将被忽略。

    这条规则源于兼容性问题和可替代性原则。由于接口或超类可以独立于它们的子类型进行泛型,我们可以用非泛型方法覆盖泛型方法。但是,覆盖(非泛型)方法必须适用于对泛型方法的调用,包括显式传递类型参数的调用。否则,子类型将无法替代其泛化的超类型。

    【讨论】:

      猜你喜欢
      • 2017-09-28
      • 1970-01-01
      • 2019-08-15
      • 1970-01-01
      • 2021-08-17
      • 1970-01-01
      • 1970-01-01
      • 2021-12-07
      • 2021-11-09
      相关资源
      最近更新 更多