Suppose that I have the following class:
public class Either<A, B> {
public Object get();
}
Either
is a type that stores one object of either type A or B. get()
retrieves that one object.
The question is whether or not it is possible to use generics to alter the method signature of get()
so that the type returned is not just Object
, but any common supertype of A and B. For example, an Either<Integer, Long>
can have get()
return Number
, an Either<Deque<T>, Set<T>>
can have get()
return Iterable<T>
or Collection<T>
, and so on. (Obviously, an Either<Foo,Foo>
should have get()
return Foo
).
If this is at all possible, if I had Either<List<A>, List<B>>
, what is the most specific type get()
can return? Is it raw List
, wildcard List<?>
, or something else entirely?
Java inference do have something similar, we can do
public static <C, A extends C, B extends C> C get(Either<A,B> e)
{ return (C)e.get(); }
inference:
A=Integer, B=Long ==> C=Number
A=List<Integer>, B=List<Long> ==> C=List<? extends Number>
usage:
Either<Integer, Long> x = ...;
get(x); // the return type is Number
However there's probably no way to turn it into an instance method. We would need to write
public class Either<A,B>
public <C super A|B> C get() { ... }
or simply
public A|B get(){ ... }
which is not supported in Java
Why not define an abstract class C, containing as much logic common to A and B as you deem necessary, and refer to that in your Either class:
public class Either<C> {
public C get();
}
That doesn't seem like much of an answer, but since Java erases your type information anyway when compiling (that it to say, your compiled code sees only Object
instead of an A
or a B
), then you are in the best position to define what should be retained in an explicit common class.
As far as I know, it is not possible: your Either<A,B>
class makes an assumption about a generic third type (let's call it C
), which both A and B would extend: while it is possible to write something like public class Either<A extends MyNonFinalClass, B extends MyNonFinalClass> {}
, Java doesn't allow forward-referencing a generic type, so you cannot even write something like Either<A extends C, B extends C, C>
. Clearly a shame, as your Either
class would really be handy :)
You need to make sure A and B share a common ancestry.
public class Either<A extends CommonAncestor, B extends CommonAncestor> {
public CommonAncestor get() {....}
}
or
public class Either<C, A extends C, B extends C> {
public C get() {....}
}
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