java - 将构造函数类型参数放在 * 之前 * 类型是什么意思?

标签 java generics syntax constructor generic-type-argument

我最近遇到了这种(对我而言)不寻常的 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>

但这不是错误,程序运行良好(我还收到有关 ListArrayList 缺少类型参数的警告,但这又是另一回事了)。

泛型类与泛型构造函数

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/

相关文章:

syntax - 特征中的 'where' 子句有什么作用?

java - 计算辛普森规则误差 < 10^-6

java - Java 中的 Levenberg-Marquardt 最小化

java - 现有 Realm 文件中字段 'String' 的无效类型 'id'

java - 为什么我不能创建字符串和通用对象的映射

Java:在实现各种树结构时我应该支持泛型吗?

swift - 如何实现一个符合相互关联协议(protocol)之一的泛型类?

syntax - Ada 中的自定义“图像”属性?

java - 如何使用java验证unix命令

string - Rust 中的 r #""# 运算符是什么?