I know the basics of generics in Java but this method I saw in my team's codebase threw me off.
default <T>ResponseEntity <T> getDataCall(){
log.info("Inside DataService");
return null;
}
I know this method's return type is using generics, meaning it is returning an object of ResponseEntity class. But why does it have T in both the left hand side and right hand side of ResponseEntity? In most of the code, I see the generic type only on the right hand side. Can someone please explain how this generic method works?
CodePudding user response:
The whitespace is misleading. It would be better if it were spaced like so:
default <T> ResponseEntity<T> getDataCall()
The first <T>
indicates that the method has a generic argument named T
. The second one is part of the return type, ResponseEntity<T>
. If you look up the ResponseEntity
type I expect you'll see that it takes a generic argument.
CodePudding user response:
The thing on the left is introducing the generic. A generic variable only exists in a particular scope, and something has to introduce that scope. Normally, you have a generic class (or interface), and that class takes type arguments, and those type arguments are in scope for the duration of the class, so they can be used as the types of function arguments or return types.
But you can also have generic functions, which is what we do here. Let's consider the difference.
class Bar<T> { ... }
interface Foo<T> {
Bar<T> getBar();
}
Here, we can have a Foo<T>
(for some specific, concrete T
), and getBar
on that Foo<T>
will always return a Bar<T>
, for that same specific T
. The type T
is fixed at the moment we declare the type of the Foo<T>
object. Now consider
class Bar<T> { ... }
interface Foo {
<T> Bar<T> getBar();
}
This interface gives us a lot more control, but it's much harder to satisfy. Now we just have one Foo
. A single instance of this Foo
type (of which there's only one; I haven't said anything about T
yet) can have its getBar
return a Bar<T>
for any T
that the caller wants, and the caller could produce a Bar<String>
and a Bar<Integer>
from the same Foo
object if they so chose. It's up to the caller at the call site of getBar
to decide what T
should be, not up to whoever instantiates the class.