在 java 中,new 关键字后面的 NonWildcardTypeArguments 的用途是什么?
In java what is the purpose of NonWildcardTypeArguments following the new keyword?
我在翻阅 java language spec 时看到了这种写创作者的方式:
Creator:
NonWildcardTypeArguments CreatedName ClassCreatorRest
明码:
new <Integer> String("1");
// or
new <String,Integer> Integer(5);
//or
new <Constructor,String,Integer> ArrayList<String>(5);
在我能想到的每个示例中,据我所知,class 列表没有用。能否请您举例说明新关键字后的类型列表何时起作用。
除非您运行进入类型可变构造函数的极其奇特java语法构造函数,否则此功能无效。从本质上讲,您永远不应该这样做。它是为了语言的完整性,可能永远不应该添加到 java.
你可以把类型参数定义放在类上,这是最常见的模式。例如,ArrayList
有一个类型变量;声明如下:
class ArrayList<E> implements List<E> { ... }
第一个 <E>
声明有某种类型 E
没有边界。然后立即使用它(第一个 <E>
和第二个 <E>
看起来相同,但一个声明类型 var,另一个是类型 var 用法,因此这些是完全不同的。到目前为止一切顺利.
但您也可以直接在方法上声明它们。例如:
public static <E> coalesce(E... items) {
for (E item : items) if (item != null) return item;
return item;
}
此方法可以使用任意数量的对象引用来调用,并且将 return 第一个不是 null
的对象引用,并且调用的类型将是所有对象引用的共同点参数。换句话说,这将编译:
String x = coalesce(null, someString, "defaultValue");
而如果我们写了它:
public static Object coalesce(Object... items) {
for (Object item : items) if (item != null) return item;
return item;
}
然后,虽然 coalesce(null, someStringRef, "default")
显然必然会 return 一个 String
,但编译器不知道这一点,因此 String x = coalesce(..)
不会编译。你必须注入演员表。泛型的重点是不必这样做。
现在回答你的问题
同样的功能(方法类型参数)在构造函数上可用:
public class Example<T> {
public <A> Example(A first, A second) {
}
}
合法java。很难想象您想要在构造函数上使用泛型的情况。构造函数没有 return 类型,重点是构造函数只需要类型参数,并且一旦你完成它就停止所有相关性(如果它与实例本身相关,你会把它在类型上,就像上面示例中的 <E>
一样)。因此,为什么您从未在 java 代码中有效地看到它。然而,如果你要写它, 和 你不希望 javac
推断泛型,而是想明确说明它,你正在阅读的语法是你会怎么做:
new <String>Example<Integer>("a", "b");
将调用该构造函数并强制 A
为 String
和 T
为 Integer
.
JLS 中有大量奇怪且令人困惑的结构,但从未有人使用过。因此,通读 JLS 通常不是一个好主意,您会学到一些东西,但这是一种非常低效的学习方式。
我在翻阅 java language spec 时看到了这种写创作者的方式:
Creator:
NonWildcardTypeArguments CreatedName ClassCreatorRest
明码:
new <Integer> String("1");
// or
new <String,Integer> Integer(5);
//or
new <Constructor,String,Integer> ArrayList<String>(5);
在我能想到的每个示例中,据我所知,class 列表没有用。能否请您举例说明新关键字后的类型列表何时起作用。
除非您运行进入类型可变构造函数的极其奇特java语法构造函数,否则此功能无效。从本质上讲,您永远不应该这样做。它是为了语言的完整性,可能永远不应该添加到 java.
你可以把类型参数定义放在类上,这是最常见的模式。例如,ArrayList
有一个类型变量;声明如下:
class ArrayList<E> implements List<E> { ... }
第一个 <E>
声明有某种类型 E
没有边界。然后立即使用它(第一个 <E>
和第二个 <E>
看起来相同,但一个声明类型 var,另一个是类型 var 用法,因此这些是完全不同的。到目前为止一切顺利.
但您也可以直接在方法上声明它们。例如:
public static <E> coalesce(E... items) {
for (E item : items) if (item != null) return item;
return item;
}
此方法可以使用任意数量的对象引用来调用,并且将 return 第一个不是 null
的对象引用,并且调用的类型将是所有对象引用的共同点参数。换句话说,这将编译:
String x = coalesce(null, someString, "defaultValue");
而如果我们写了它:
public static Object coalesce(Object... items) {
for (Object item : items) if (item != null) return item;
return item;
}
然后,虽然 coalesce(null, someStringRef, "default")
显然必然会 return 一个 String
,但编译器不知道这一点,因此 String x = coalesce(..)
不会编译。你必须注入演员表。泛型的重点是不必这样做。
现在回答你的问题
同样的功能(方法类型参数)在构造函数上可用:
public class Example<T> {
public <A> Example(A first, A second) {
}
}
合法java。很难想象您想要在构造函数上使用泛型的情况。构造函数没有 return 类型,重点是构造函数只需要类型参数,并且一旦你完成它就停止所有相关性(如果它与实例本身相关,你会把它在类型上,就像上面示例中的 <E>
一样)。因此,为什么您从未在 java 代码中有效地看到它。然而,如果你要写它, 和 你不希望 javac
推断泛型,而是想明确说明它,你正在阅读的语法是你会怎么做:
new <String>Example<Integer>("a", "b");
将调用该构造函数并强制 A
为 String
和 T
为 Integer
.
JLS 中有大量奇怪且令人困惑的结构,但从未有人使用过。因此,通读 JLS 通常不是一个好主意,您会学到一些东西,但这是一种非常低效的学习方式。