For how var
works, refer to section 14.4.1 of the JLS.
If the LocalVariableType is var
, then let T be the type of the initializer expression when treated as if it did not appear in an assignment context, and were thus a standalone expression (§15.2). The type of the local variable is the upward projection of T with respect to all synthetic type variables mentioned by T (§4.10.5).
To know how the type parameter gets inferred, refer to section 15.12.2.6, where it specifies how the invocation type is determined
If the chosen method is generic and the method invocation does not provide explicit type arguments, the invocation type is inferred as specified in §18.5.2.
Digging deeper into 18.5.2, we find a lot of rules that are not relevant to your situation - about the case of poly expressions (which the method call in the initialiser of var
can never be). In the case of not using var
, more bounds would be added in this step. It also mentioned what additional bounds to add when there are argument expressions (which your method has none). The relevant part is that T
is eventually resolved (section 18.4).
What constraints are on T
? Well, you did not write T extends Something
, so the only bound is T <: Object
. (See the end of section 18.1.3) This just means T
must be a subtype of Object
. In other words, Object
is the only lower bound of T
. If you declare the method with <T extend SomeOtherType>
, then it would have SomeOtherType
as a lower bound.
The section about resolution is quite long, but the relevant thing here is that lower bounds are resolved to their least upper bound, a super type that is more specific than any other common super type the types have.
Since we only have one lower bound, Object
, its least upper bound is trivially itself. Therefore, T
is inferred to be Object
. You can see this by adding the --debug=verboseResolution=all
option when compiling:
JavaClass.java:8: Note: resolving method create in type JavaClass to candidate 0
var s = create();
^
phase: BASIC
with actuals: no arguments
with type-args: no arguments
candidates:
#0 applicable method found: <T>create()
(partially instantiated to: ()Set<Object>)
where T is a type-variable:
T extends Object declared in method <T>create()
JavaClass.java:8: Note: Deferred instantiation of method <T>create()
var s = create();
^
instantiated signature: ()Set<Object>
target-type: <none>
where T is a type-variable:
T extends Object declared in method <T>create()
get()
supposed to be the same ascreate()
in this example? – Myoglobin