简体   繁体   English

Java方法和泛型

[英]Java methods and generics

Why are generics declared as part of a method? 为什么泛型被声明为方法的一部分? For instance, when creating a method that uses generics, the generics must be included after the method modifiers: 例如,在创建使用泛型的方法时,必须在方法修饰符之后包含泛型:

public static <T, K> void delete(AbstractDao<T, K> dao)

The generics portion of a method is not shown as part of a method declaration. 方法的泛型部分未显示为方法声明的一部分。 According to java documentation, methods contain the following items: 根据java文档,方法包含以下项目:

Modifiers—such as public, private, and others you will learn about later. 修改器 - 例如公共,私人和其他您将在稍后了解的内容。

The return type—the data type of the value returned by the method, or void if the method does not return a value. 返回类型 - 方法返回的值的数据类型,如果方法未返回值,则返回void。

The method name—the rules for field names apply to method names as well, but the convention is a little different. 方法名称 - 字段名称的规则也适用于方法名称,但约定略有不同。

The parameter list in parenthesis—a comma-delimited list of input parameters, preceded by their data types, enclosed by parentheses, (). 括号中的参数列表 - 以逗号分隔的输入参数列表,前面是数据类型,括在括号中,()。 If there are no parameters, you must use empty parentheses. 如果没有参数,则必须使用空括号。

Reference: https://docs.oracle.com/javase/tutorial/java/javaOO/methods.html 参考: https//docs.oracle.com/javase/tutorial/java/javaOO/methods.html

This is because you have to consider separately generic type parameters declaration and usage . 这是因为您必须单独考虑泛型类型参数声明用法

In a method declaration without the first <T,K> , like this: 在没有第一个<T,K>的方法声明中,如下所示:

public static void delete(AbstractDao<T, K> dao)

the compiler wouldn't know that T and K are supposed to be method type parameters (inferred from the method call). 编译器不会知道TK应该是方法类型参数(从方法调用推断)。 It would expect T and K to be already declared (eg imported), because these are usages of generics, not declarations. 它会期望TK已经被声明(例如导入),因为这些是泛型的用法 ,而不是声明。

That's why you need the declaration <T, K> after the modifiers for the compiler, telling it that T and K are type parameters inferred from the method call. 这就是为什么你需要在编译器的修饰符之后声明<T, K> ,告诉它TK是从方法调用中推断出的类型参数。

The problem does not occur when you declare a generic class like this: 当您声明这样的泛型类时,不会发生此问题:

public class MyClass<T> {
}

because there is no other meaning T could have here, that can only be a type parameter declaration . 因为T在这里没有其他含义,只能是类型参数声明


Note: you can also tell the difference between declarations and usages, because you can constrain a type parameter during its declaration, but not during its usage. 注意:您还可以区分声明和用法之间的区别,因为您可以在声明期间约束类型参数,但不能在使用期间约束类型参数。 This is valid: 这是有效的:

public static <T extends Pony, K> void delete(AbstractDao<T, K> dao)

While this is not: 虽然这不是:

public static <T, K> void delete(AbstractDao<T extends Pony, K> dao)

Why isn't the compiler smarter? 为什么编译器不聪明?

You could tell me that the compiler could be smart and it could see that the type is not declared, and deduce it is supposed to be generic. 你可以告诉我,编译器可能很聪明,它可以看到没有声明类型,推断它应该是通用的。 But it would really be a mess if it were so. 但如果是这样的话,那真是一团糟。

In most cases your method won't be generic. 在大多数情况下,您的方法不是通用的。 In most cases, a parameter like List<Something> would be used where Something is actually defined already. 在大多数情况下,如果已经实际定义了Something则会使用List<Something>类的参数。 Imagine if you simply forget to import the Something class... 想象一下,如果你只是忘记导入Something类......

The compiler would assume a generic type parameter, erased by object, and you would not understand why you're not able to use your class's methods etc. It would take some time to realize what's wrong, because the compiler would accept such a declaration. 编译器将假设一个泛型类型参数,由对象擦除,你不明白为什么你不能使用你的类的方法等。它需要一些时间才能意识到什么是错的,因为编译器会接受这样的声明。

For a more authoritative and complete source of documentation, you should refer to the Java Language Specification. 有关更权威和完整的文档资源,请参阅Java语言规范。 Specifically in this case section 8.4 on method declarations where they explicitly mention type parameters: 特别是在这个案例的8.4节方法声明中 ,他们明确提到了类型参数:

A method declares executable code that can be invoked, passing a fixed number of values as arguments. 方法声明可以调用的可执行代码,将固定数量的值作为参数传递。

MethodDeclaration:

{MethodModifier} MethodHeader MethodBody

MethodHeader:

Result MethodDeclarator [Throws]

TypeParameters {Annotation} Result MethodDeclarator [Throws] TypeParameters {Annotation} Result MethodDeclarator [Throws]

MethodDeclarator:

Identifier ( [FormalParameterList] ) [Dims]

来自http://math.hws.edu/javanotes/c10/s5.html “我们需要使用类型参数的名称替换方法定义中的特定类型String,例如T.但是,如果这是只有我们改变,编译器会认为“T”是实际类型的名称,它会将其标记为未声明的标识符。我们需要某种方式告诉编译器“T”是一个类型参数。这就是什么<T>在泛型类“class Queue <T> {...”的定义中执行。对于泛型方法,<T>就在方法的返回类型的名称之前“所以,< T>在方法名称告诉编译器方法签名中的T不是实际类型,而是泛型。

Generics is just an abbreviation for “generic types”, that can be expressed for return types or for parameter types (like in your case: AbstractDao<T, K> ). 泛型只是“泛型类型”的缩写,可以表示返回类型或参数类型(如您的情况: AbstractDao<T, K> )。 And the syntax of the language requires that the type variables specified in the generic types should be declared before the return type of the method, so that they can encompass both return as well as parameter types. 并且语言的语法要求在泛型类型中指定的类型变量应该在方法的返回类型之前声明,以便它们可以包含返回和参数类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM