Suppose I have a method "mix" that takes two Lists of possibly different types T and S and returns a single List containing the elements of both. For type-safety, I'd like to specify that the returned List is of a type R, where R is a supertype common to both T and S. For example:
List<Number> foo = mix(
Arrays.asList<Integer>(1, 2, 3),
Arrays.asList<Double>(1.0, 2.0, 3.0)
);
To specify this, I could declare the method as
static <R, T extends R, S extends R> List<R> mix(List<T> ts, List<S> ss)
But what if I want to make mix
an instance method instead of static, on the class List2<T>
?
<R, T extends R, S extends R> List<R> mix ...
shadows the <T>
on the instance of List2
, so that's no good.
<R, T extends S&T, S extends R> List<R> mix ...
solves the shadowing problem, but isn't accepted by the compiler
<R super T, S extends R> List<R> mix ...
is rejected by the compiler because lower-bounded wildcards can't be stored in a named variable (only used in ? super X
expressions)
I could move the arguments to the class itself, like List2<R, T extends R, S extends R>
, but the type information really has no business being on the instance level, because it's only used for one method call, and you would have to re-cast the object every time you wanted to invoke the method on different arguments.
As far as I can tell, there's no way to do this with generics. The best I can do would be to return a raw List2
and cast it at the callsite, like before generics were introduced. Does anybody have a better solution?
S extends T
instead ofS extends R
? – Mezamix
. What exactly are you doing in it? Do you really need those those type parameters? It looks like you can go with bounded wildcards instead. – MezaR
type parameter. Since you just intend to return aList<Number>
, then just have that as return type. Frankly speaking, I don't see any use of generic method here. – MezaList<Number>
part is just an example. I want it to be able to mix any two types. A trivial implementation ofmix
could be justArrayList<R> result = new ArrayList<>(ts.size() + ss.size()); result.addAll(ts); result.addAll(ss); return result;
– Jadejaded<R super T, S extends R> List<R>
is really the signature that would make sense. Related post: Bounding generics with 'super' keyword. You may have to settle for keeping it a static method. – BackandforthT
againstR
in the declartion of the typeList2
. Which would simply be moving the type parameters in the method declaration to the class declartion:class List2<R, T extends R, S extends R>
, which I assume is not what you wanted. – DisentwineR super T
is not supported. – Meza