I was looking through the java language spec and saw this way of writing a creator:
Creator:
NonWildcardTypeArguments CreatedName ClassCreatorRest
In plain code:
new <Integer> String("1");
// or
new <String,Integer> Integer(5);
//or
new <Constructor,String,Integer> ArrayList<String>(5);
In every example I can think of the class list is not useful as far as I can tell. Can you please give me an example when the typelist after the new keyword serves a purpose.
CodePudding user response:
This feature is invalid unless you run into the extremely exotic java syntactical constructor of a type-varred constructor. Essentially, you should never be doing this. It's there for language completeness and probably should never have been added to java.
You can put type param definitions on classes, this is the most common mode. For example, ArrayList
has a type variable; it is declared as follows:
class ArrayList<E> implements List<E> { ... }
The first <E>
declares that there is some type E
with no bounds. It is then used immediately (the first <E>
and the second <E>
look identical, but one declares the type var, the other is a type var usage, and thus these are quite different. So far so good.
But you can also declare them directly on a method. For example:
public static <E> coalesce(E... items) {
for (E item : items) if (item != null) return item;
return item;
}
This method can be invoked with as many object refs as you please and will return the first one that isn't null
, and the invocation's type will be the common denominator amongst all the parameters. In other words, this would compile:
String x = coalesce(null, someString, "defaultValue");
Whereas if we had written it:
public static Object coalesce(Object... items) {
for (Object item : items) if (item != null) return item;
return item;
}
Then, whilst coalesce(null, someStringRef, "default")
would obviously neccessarily return a String
, the compiler doesn't know that and thus String x = coalesce(..)
would NOT compile. You'd have to inject a cast. The point of generics is to not have to do that.
And now to the answer to your question
This same feature (on-method type params) is available on constructors:
public class Example<T> {
public <A> Example(A first, A second) {
}
}
is legal java. It is extremely difficult to attempt to think of a situation where you'd want on-constructor generics. Constructors have no return type, and the whole point is that the typeparam is needed just for the constructor and ceases all relevance once you're done with it (if it is relevant to the instance itself, you'd put it on the type, just like <E>
in the example above). Hence why you see it effectively never in java code. Nevertheless, if you were to write it, and you don't want javac
to infer the generics but instead want to be explicit about it, the syntax you are reading about is how you'd do it:
new <String>Example<Integer>("a", "b");
Would invoke that constructor and force A
to be String
and T
to be Integer
.
There are boatloads of weird and confusing constructs in the JLS that nobody ever uses. Hence it's not generally a good idea to just read through the JLS, you'll learn something but it is a highly inefficient way of learning things.