构造函数类型参数放在类型*之前*意味着什么?
What do constructor type arguments mean when placed *before* the type?
我最近遇到了这种不寻常的(对我来说)Java 语法...这是一个例子:
List list = new <String, Long>ArrayList();
注意 <String, Long>
类型参数的位置……它不是在正常类型之后,而是在类型之前。我不介意承认我以前从未见过这种语法。另请注意,当 ArrayList
只有 1 个时,有 2 个类型参数。
类型参数的定位是否与将它们放在类型之后的含义相同?如果不是,不同的定位是什么意思?
为什么在 ArrayList
只有 1 个类型参数时有 2 个类型参数是合法的?
我搜索了常见的地方,例如。 Angelika Langer 等,但除了 ANTLR 项目 Java 语法文件中的语法规则外,找不到任何提及此语法的地方。
调用通用构造函数
这很不寻常,但完全有效 Java。要理解我们需要知道一个 class 可能有一个泛型构造函数,例如:
public class TypeWithGenericConstructor {
public <T> TypeWithGenericConstructor(T arg) {
// TODO Auto-generated constructor stub
}
}
我想在通过泛型构造函数实例化 class 时,我们通常不需要显式显示类型参数。例如:
new TypeWithGenericConstructor(LocalDate.now(ZoneId.systemDefault()));
现在T
显然是LocalDate
。但是,可能存在 Java 无法推断(推导)类型参数的情况。然后我们使用您问题中的语法明确提供它:
new <LocalDate>TypeWithGenericConstructor(null);
当然,如果我们认为它有助于提高可读性或出于任何原因,即使没有必要,我们也可以提供它:
new <LocalDate>TypeWithGenericConstructor(LocalDate.now(ZoneId.systemDefault()));
在您的问题中,您似乎在调用 java.util.ArrayList
构造函数。该构造函数不是通用的(只有 ArrayList
class 作为一个整体是通用的,那是另外一回事)。为什么 Java 允许您在不使用时在调用中提供类型参数,请参阅下面我的编辑。我的 Eclipse 给我一个 警告:
Unused type arguments for the non generic constructor ArrayList() of
type ArrayList; it should not be parameterized with arguments <String,
Long>
但这不是错误,程序运行良好(我还收到有关 List
和 ArrayList
缺少类型参数的警告,但这又是另一回事了)。
泛型 class 与泛型构造函数
Does the positioning of the type arguments have the same meaning as
putting them after the type? If not, what does the different
positioning mean?
不,不一样。通常的类型 argument/s 在 之后,类型 (ArrayList<Integer>()
) 用于 generic class。类型参数 before 用于 constructor.
这两种形式也可以结合使用:
List<Integer> list = new <String, Long>ArrayList<Integer>();
我认为这更正确一些,因为我们现在可以看到列表存储 Integer
个对象(当然,我仍然更愿意省略无意义的 <String, Long>
)。
Why is it legal to have 2 type arguments when ArrayList only has 1?
首先,如果你在类型之前提供类型参数,你应该为构造函数提供正确的数字,而不是class,所以它与有多少类型参数没有任何关系ArrayList
class 已经搞定了。这实际上意味着在这种情况下您不应该提供任何参数,因为构造函数不接受类型参数(它不是泛型的)。无论如何,当你提供一些时,它们会被忽略,这就是为什么你提供多少并不重要。
为什么允许无意义的类型参数?
感谢@Slaw 为 link 编辑:Java 允许在所有方法调用上使用类型参数。如果被调用的方法是泛型的,则使用类型参数;如果不是,它们将被忽略。例如:
int length = "My string".<List>length();
是的,这很荒谬。 Java 语言规范 (JLS) 在第 15.12.2.1 小节中给出了此理由:
This rule stems from issues of compatibility and principles of substitutability. Since interfaces or superclasses may be generified
independently of their subtypes, we may override a generic method with
a non-generic one. However, the overriding (non-generic) method must
be applicable to calls to the generic method, including calls that
explicitly pass type arguments. Otherwise the subtype would not be
substitutable for its generified supertype.
该参数不适用于构造函数,因为它们不能被直接覆盖。但我想他们想要有相同的规则,以免让已经很复杂的规则变得过于复杂。无论如何,关于实例化的第 15.9.3 节和 new
不止一次引用 15.12.2.
链接
显然,您可以在任何非通用 method/constructor 前加上您喜欢的任何通用参数:
new <Long>String();
Thread.currentThread().<Long>getName();
编译器不关心,因为它不必将这些类型参数与实际的泛型参数相匹配。
一旦编译器必须检查参数,它就会抱怨不匹配:
Collections.<String, Long>singleton("A"); // does not compile
对我来说似乎是一个编译器错误。
我最近遇到了这种不寻常的(对我来说)Java 语法...这是一个例子:
List list = new <String, Long>ArrayList();
注意 <String, Long>
类型参数的位置……它不是在正常类型之后,而是在类型之前。我不介意承认我以前从未见过这种语法。另请注意,当 ArrayList
只有 1 个时,有 2 个类型参数。
类型参数的定位是否与将它们放在类型之后的含义相同?如果不是,不同的定位是什么意思?
为什么在 ArrayList
只有 1 个类型参数时有 2 个类型参数是合法的?
我搜索了常见的地方,例如。 Angelika Langer 等,但除了 ANTLR 项目 Java 语法文件中的语法规则外,找不到任何提及此语法的地方。
调用通用构造函数
这很不寻常,但完全有效 Java。要理解我们需要知道一个 class 可能有一个泛型构造函数,例如:
public class TypeWithGenericConstructor {
public <T> TypeWithGenericConstructor(T arg) {
// TODO Auto-generated constructor stub
}
}
我想在通过泛型构造函数实例化 class 时,我们通常不需要显式显示类型参数。例如:
new TypeWithGenericConstructor(LocalDate.now(ZoneId.systemDefault()));
现在T
显然是LocalDate
。但是,可能存在 Java 无法推断(推导)类型参数的情况。然后我们使用您问题中的语法明确提供它:
new <LocalDate>TypeWithGenericConstructor(null);
当然,如果我们认为它有助于提高可读性或出于任何原因,即使没有必要,我们也可以提供它:
new <LocalDate>TypeWithGenericConstructor(LocalDate.now(ZoneId.systemDefault()));
在您的问题中,您似乎在调用 java.util.ArrayList
构造函数。该构造函数不是通用的(只有 ArrayList
class 作为一个整体是通用的,那是另外一回事)。为什么 Java 允许您在不使用时在调用中提供类型参数,请参阅下面我的编辑。我的 Eclipse 给我一个 警告:
Unused type arguments for the non generic constructor ArrayList() of type ArrayList; it should not be parameterized with arguments <String, Long>
但这不是错误,程序运行良好(我还收到有关 List
和 ArrayList
缺少类型参数的警告,但这又是另一回事了)。
泛型 class 与泛型构造函数
Does the positioning of the type arguments have the same meaning as putting them after the type? If not, what does the different positioning mean?
不,不一样。通常的类型 argument/s 在 之后,类型 (ArrayList<Integer>()
) 用于 generic class。类型参数 before 用于 constructor.
这两种形式也可以结合使用:
List<Integer> list = new <String, Long>ArrayList<Integer>();
我认为这更正确一些,因为我们现在可以看到列表存储 Integer
个对象(当然,我仍然更愿意省略无意义的 <String, Long>
)。
Why is it legal to have 2 type arguments when ArrayList only has 1?
首先,如果你在类型之前提供类型参数,你应该为构造函数提供正确的数字,而不是class,所以它与有多少类型参数没有任何关系ArrayList
class 已经搞定了。这实际上意味着在这种情况下您不应该提供任何参数,因为构造函数不接受类型参数(它不是泛型的)。无论如何,当你提供一些时,它们会被忽略,这就是为什么你提供多少并不重要。
为什么允许无意义的类型参数?
感谢@Slaw 为 link 编辑:Java 允许在所有方法调用上使用类型参数。如果被调用的方法是泛型的,则使用类型参数;如果不是,它们将被忽略。例如:
int length = "My string".<List>length();
是的,这很荒谬。 Java 语言规范 (JLS) 在第 15.12.2.1 小节中给出了此理由:
This rule stems from issues of compatibility and principles of substitutability. Since interfaces or superclasses may be generified independently of their subtypes, we may override a generic method with a non-generic one. However, the overriding (non-generic) method must be applicable to calls to the generic method, including calls that explicitly pass type arguments. Otherwise the subtype would not be substitutable for its generified supertype.
该参数不适用于构造函数,因为它们不能被直接覆盖。但我想他们想要有相同的规则,以免让已经很复杂的规则变得过于复杂。无论如何,关于实例化的第 15.9.3 节和 new
不止一次引用 15.12.2.
链接
显然,您可以在任何非通用 method/constructor 前加上您喜欢的任何通用参数:
new <Long>String();
Thread.currentThread().<Long>getName();
编译器不关心,因为它不必将这些类型参数与实际的泛型参数相匹配。
一旦编译器必须检查参数,它就会抱怨不匹配:
Collections.<String, Long>singleton("A"); // does not compile
对我来说似乎是一个编译器错误。