Nat*_*ams 126 java generics syntax constructor generic-type-argument
最近,我遇到了这种不寻常的(对我来说)Java语法...下面是一个示例:
List list = new <String, Long>ArrayList();
Run Code Online (Sandbox Code Playgroud)
请注意<String, Long>类型参数的位置...它不是在普通类型之后,而是之前。我不介意承认我以前从未见过这种语法。另请注意,ArrayList只有1个时有2个类型参数。
类型参数的位置是否与将其放在类型后面的含义相同?如果不是,不同的定位是什么意思?
为什么ArrayList只有1 个类型有2个类型参数是合法的?
我搜寻了平常的地方,例如。Angelika Langer等人在这里,但是除了ANTLR项目的Java语法文件中的语法规则之外,找不到任何关于此语法的提及。
Ole*_*.V. 141
没关系,但是Java是完全有效的。要理解,我们需要知道一个类可能具有通用构造函数,例如:
public class TypeWithGenericConstructor {
public <T> TypeWithGenericConstructor(T arg) {
// TODO Auto-generated constructor stub
}
}
Run Code Online (Sandbox Code Playgroud)
我想通过泛型构造函数实例化类时,我们通常不需要显式声明类型参数。例如:
new TypeWithGenericConstructor(LocalDate.now(ZoneId.systemDefault()));
Run Code Online (Sandbox Code Playgroud)
现在T很明显LocalDate。但是,在某些情况下,Java无法推断(推导)type参数。然后,使用您问题的语法明确提供它:
new <LocalDate>TypeWithGenericConstructor(null);
Run Code Online (Sandbox Code Playgroud)
当然,即使我们认为它有助于提高可读性或出于任何原因,也可以提供它,即使它不是必需的:
new <LocalDate>TypeWithGenericConstructor(LocalDate.now(ZoneId.systemDefault()));
Run Code Online (Sandbox Code Playgroud)
在您的问题中,您似乎正在调用java.util.ArrayList构造函数。该构造函数不是通用的(仅整个ArrayList类是这样)。关于为什么Java允许您在不使用类型参数时在调用中提供它们的原因,请参见下面的编辑。我的Eclipse给了我一个警告:
ArrayList类型的非泛型构造函数ArrayList()的未使用类型参数;不应使用参数对其进行参数化
但它不是一个错误,并且该程序运行正常(我还得到警告有关缺失类型参数List和ArrayList,但是这又是一个不同的故事)。
类型参数的位置是否与将其放在类型后面的含义相同?如果不是,不同的定位是什么意思?
不,不一样 type()之后的通常类型参数ArrayList<Integer>()是针对泛型类的。之前的类型参数用于构造函数。
两种形式也可以结合使用:
List<Integer> list = new <String, Long>ArrayList<Integer>();
Run Code Online (Sandbox Code Playgroud)
我认为这会更正确,因为我们现在可以看到列表存储了Integer对象(当然,我仍然希望忽略无意义<String, Long>的对象)。
当ArrayList只有1个类型时,为什么拥有2个类型参数是合法的?
首先,如果在类型之前提供类型实参,则应该为构造函数而不是为类提供正确的数字,因此与ArrayList该类有多少个类型实参没有任何关系。这实际上意味着在这种情况下您不应该提供任何内容,因为构造函数不接受类型参数(这不是通用的)。无论如何,当您提供一些东西时,它们都会被忽略,这就是为什么无论您提供多少根都无关紧要。
感谢@Slaw进行链接编辑:Java允许在所有方法调用上使用类型参数。如果被调用的方法是通用的,则使用类型参数。如果不是,它们将被忽略。例如:
int length = "My string".<List>length();
Run Code Online (Sandbox Code Playgroud)
是的,这很荒谬。Java语言规范(JLS)在第15.12.2.1小节中提供了这一理由:
该规则源于兼容性和可替代性原则。由于接口或超类的生成可以独立于其子类型,因此我们可以用非泛型方法覆盖泛型方法。但是,重写(非泛型)方法必须适用于对泛型方法的调用,包括显式传递类型实参的调用。否则,该亚型将无法替代其生成的超型。
该参数不适用于构造函数,因为不能直接覆盖它们。但是我想他们希望拥有相同的规则,以免使已经很复杂的规则变得过于复杂。无论如何,关于实例化的15.9.3节new不止一次提到了15.12.2。
| 归档时间: |
|
| 查看次数: |
5798 次 |
| 最近记录: |