How are references to << T >> handled by the compiler in the following code, since the method takes no parameters that would allow inference of T? Are any restrictions being placed on what type of object can be placed into the list? Is a cast even taking place on the line where I add the String to the list? My first thought is that without anything to infer T from, T becomes an Object type. Thanks in advance.
public class App {
private <T> void parameterizedMethod()
{
List<T> list = new ArrayList<>();
for(int i = 0; i < 10; i++)
{
list.add((T)new String()); //is a cast actually occurring here?
}
}
public App()
{
parameterizedMethod();
}
public static void main(String[] args) {
new App();
}
}
This is initially determined by 18.1.3:
When inference begins, a bound set is typically generated from a list of type parameter declarations
P1, ..., Pp
and associated inference variablesα1, ..., αp
. Such a bound set is constructed as follows. For each l (1 ≤ l ≤ p):
If
Pl
has noTypeBound
, the boundαl <: Object
appears in the set.Otherwise, for each type
T
delimited by&
in theTypeBound
, the boundαl <: T[P1:=α1, ..., Pp:=αp]
appears in the set; [...].
At the end of inference, the bound set gets "resolved" to the inferred type. Without any additional context, the bound set will only consist of the initial bounds based on the declaration of the type parameter.
A bound with a form like αl <: Object
means αl
(an inference variable) is Object
or a subtype of Object
. This bound is resolved to Object
.
So in your case, yes, Object
is inferred.
If we declared a type bound:
private <T extends SomeType> void parameterizedMethod()
then SomeType
will be inferred.
No cast actually happens in this case (erasure). That's why it's "unchecked". A cast only happens when the object is exposed due to e.g.:
<T> T parameterizedMethodWithAResult()
{
return (T) new String();
}
// the cast happens out here
Integer i = parameterizedMethodWithAResult();
// parameterizedMethodWithAResult returns Object actually,
// and we are implicitly doing this:
Integer i = (Integer) parameterizedMethodWithAResult();
Are any restrictions being placed on what type of object can be placed into the list?
Semantically (compile-time), yes. And note that the restriction is determined outside the method. Inside the method, we don't know what that restriction actually is. So we should not be putting String
in a List<T>
. We don't know what T
is.
Practically (run-time), no. It's just a List
and there's no checked cast. parameterizedMethod
won't cause an exception...but that only holds for this kind of isolated example. This kind of code may very well lead to issues.
Inside the method body, Java provides us no way to get any information about the substitution for T
, so how can we do anything useful with T
?
Sometimes, T
is not really important to the method body; it's just more convenient for the caller
public static List<T> emptyList(){...}
List<String> emptyStringList = emptyList();
But if T
is important to method body, there must be an out-of-band protocol, not enforceable by the compiler, that both the caller and the callee must obey. For example
class Conf
<T> T get(String key)
//
<conf>
<param name="size" type="int" ...
//
String name = conf.get("name");
Integer size = conf.get("size");
The API uses <T>
here just so that the caller doesn't need to do an explicit cast. It is the caller's responsibility to ensure that the correct T
is supplied.
In your example, the callee assumes that T
is a supertype of String
; the caller must uphold that assumption. It would be nice if such constraint can be expressed to the compiler as
<T super String> void parameterizedMethod()
{
List<T> list
...
list.add( new String() ); // obviously correct; no cast is needed
}
//
this.<Integer>parameterizedMethod(); // compile error
unfortunately, java does not support <T super Foo>
... :) So you need to javadoc the constraint instead
/** T must be a supertype of String! **/
<T> void parameterizedMethod()
I have an actual API example just like that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With