Consider the following constructor for the class Foo
(which for the sake of clarity is not a generic class):
public <T> Foo(T obj) { }
This is valid syntax for constructors, just like with normal generic methods.
But what is the use of this syntax? Typically generic methods provide type safety for their return type, and can benefit from type inference by the compiler. For example:
Pair<String, Integer> stringInt = Pair.of("asfd", 1234);
But a call to a constructor always returns an instance of its declaring class, so its type parameters have no effect on the return type. The constructor above could just be replaced with its erasure:
public Foo(Object obj) { }
Of course generics aren't only about type safety for return types. The constructor might just want to constrain the type of argument(s) being passed in. However, the above reasoning still applies for a bounded type parameter:
public <N extends Number> Foo(N number) { }
public Foo(Number number) { } //same thing
Even nested type parameters with bounds are handled using wildcards:
public <N extends Number, L extends List<N>> Foo(L numList) { }
public Foo(List<? extends Number> numList) { } //same thing
So what is a legitimate use case for having a generic constructor?
Here's a possible one, adapted from functional programming. Suppose we have a Stream
type that has some internal state, repeatedly yielding new elements until it returns null
. The outside callers don't care what the internal state type of the stream type is, so you might get something like
class Stream<E> {
<S> Stream(S initialState, StepFunction<E, S> stepFun) {
...
}
}
without the recipient having to know what the internal state type is.
One thing I can think off of the top of my head is that you can ensure that bounds are fulfilled in the same way across multiple parameters.
Take an obviously stupid and contrived but valid constructor that copies a list from a source to a target:
public <T> Foo (List<T> listA, List<T> listB) {
listA.addAll(listB);
}
Using wildcards here would quickly become pretty nasty and probably not do what you want anyway. It would also be a totally arbitrary restriction to disallow it. So it makes sense to me that the language spec allows it.
One use case that I can think of is when you want to constrain a constructor argument to more than one type. Only the generic syntax allows you to declare a constructor taking a List
of Number
s that also implements RandomAccess
:
public <L extends List<? extends Number> & RandomAccess> Foo(L raNumList) { }
...
Foo f1 = new Foo(new ArrayList<Integer>());
Foo f2 = new Foo(new LinkedList<Integer>()); //compiler error
You can enforce certain constraints for the constructor parameters. E.g. the following code requires two parameters which implement the interfaces InterfaceA and InterfaceB.
<T extends InterfaceA & InterfaceB > Foo(T t1, T t2) {
}
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