我最近遇到了这种(对我而言)不寻常的 Java 语法......这是一个例子:
List list = new <String, Long>ArrayList();
注意 <String, Long>
的位置类型参数......它不是在正常类型之后而是在之前。我不介意承认我以前从未见过这种语法。另请注意,ArrayList
时有 2 个类型参数。只有 1 个。
类型参数的位置是否与将它们放在类型之后具有相同的含义?如果不是,不同的定位是什么意思?
为什么 ArrayList
时有 2 个类型参数是合法的只有 1 个?
我已经搜索了常见的地方,例如。 Angelika Langer 和在此处,但除了 ANTLR 项目的 Java 语法文件中的语法规则之外,找不到任何提及此语法的任何地方。
最佳答案
调用泛型构造函数
这是不寻常的,但完全有效的 Java。要理解我们需要知道一个类可能有一个泛型构造函数,例如:
public class TypeWithGenericConstructor {
public <T> TypeWithGenericConstructor(T arg) {
// TODO Auto-generated constructor stub
}
}
我想在通过泛型构造函数实例化类时,我们通常不需要显式指定类型参数。例如:
new TypeWithGenericConstructor(LocalDate.now(ZoneId.systemDefault()));
现在 T
显然是 LocalDate
.但是,可能存在 Java 无法推断(推断)类型参数的情况。然后我们使用您问题中的语法明确地提供它:
new <LocalDate>TypeWithGenericConstructor(null);
当然,如果我们认为它有助于可读性或出于任何原因,我们也可以提供它,即使它不是必需的:
new <LocalDate>TypeWithGenericConstructor(LocalDate.now(ZoneId.systemDefault()));
在您的问题中,您似乎正在调用 java.util.ArrayList
构造函数。该构造函数不是通用的(只有 ArrayList
类作为一个整体是,那是别的东西)。关于为什么 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
缺少类型参数的警告,但这又是另一回事了)。
泛型类与泛型构造函数
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?
不,不一样。通常的类型参数/s 在类型(ArrayList<Integer>()
)用于通用类。类型参数 before 用于 构造函数。
这两种形式也可以结合使用:
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?
首先,如果你在类型之前提供类型参数,你应该为构造函数提供正确的数字,而不是为类,所以它与 ArrayList
有多少类型参数没有任何关系。上课了。这实际上意味着在这种情况下您不应该提供任何内容,因为构造函数不接受类型参数(它不是通用的)。当你无论如何提供一些时,它们会被忽略,这就是为什么你提供多少或多少并不重要。
为什么允许无意义的类型参数?
感谢@Slaw 的链接进行编辑: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。
链接
关于java - 将构造函数类型参数放在 * 之前 * 类型是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55330697/