mattfred
mattfred

Reputation: 2749

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:

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.

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

Upvotes: 8

Views: 429

Answers (4)

Joffrey
Joffrey

Reputation: 37660

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:

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). It would expect T and K to be already declared (e.g. imported), because these are usages of generics, not declarations.

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.

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.


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. Imagine if you simply forget to import the Something class...

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.

Upvotes: 10

Lee
Lee

Reputation: 41

From http://math.hws.edu/javanotes/c10/s5.html "We need to replace the specific type String in the definition of the method with the name of a type parameter, such as T. However, if that's the only change we make, the compiler will think that "T" is the name of an actual type, and it will mark it as an undeclared identifier. We need some way of telling the compiler that "T" is a type parameter. That's what the < T > does in the definition of the generic class "class Queue< T > { ...". For a generic method, the < T > goes just before the name of the return type of the method" So, the < T > before the method name tells the compiler that the T in the method signature is not an actual type, but a generic.

Upvotes: 1

M A
M A

Reputation: 72844

For a more authoritative and complete source of documentation, you should refer to the Java Language Specification. Specifically in this case section 8.4 on method declarations where they explicitly mention type parameters:

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]

MethodDeclarator:

Identifier ( [FormalParameterList] ) [Dims]

Upvotes: 3

Renzo
Renzo

Reputation: 27414

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>). 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.

Upvotes: 1

Related Questions