Multiple wildcard bounds - java

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() {....}
}

Related

How to overload generic function with more specific type parameter?

Suppose I have a generic class
public class A<T> {}
Then , A is instantiated with B and C, with C extends from another class D :
public class B {}
public class C extends D {}
A<B> b = new A<>();
A<C> c = new A<>();
What I'm trying to do is creating a method which accepts A<T> a as a parameter. However, I plan to overload the function, so that the instance whose type parameter extends from D can be handled differently.
public class X {
public static void fun(A<?> a) {}
public static void fun(A<? extends D> a) {}
}
However, the code above cannot be compiled, since it seems that the second func also bounds to Object. My question would be how to handle such case ? Should I just use instanceof , or is there any neater way to accomplish this ?
Edit : I'm trying to create a function which can handle specific classes with overloading, but there's a catch-all function that will handle other non-specified classes, since I cannot know in advance what classes are going to be used for the type parameter
it seems that the second func also bounds to Object
That is incorrect.
Because of type erasure, the generics are removed, so they both become:
public static void fun(A a) {}
public static void fun(A a) {}
Solution: Don't use overloading, use different method names.

Java wildcarding with multiple types in variable

I know it is possible to wildcard with multiple types in case of methods and classes but what about variables? E.g. can I require an ArrayList to only take elements that implement both of two different interfaces that are not in the same type hierarchy? See code below for what I am trying to do.
import java.util.ArrayList;
interface A {}
interface B{}
interface AB extends A, B{}
class D <T extends A & B> { //This works but this is a class
T variable;
}
public class C {
ArrayList<AB> myList1 = new ArrayList<AB>(); // compiles
ArrayList<? extends AB> myList3 = new ArrayList<AB>(); //compiles
//The following does not compile.
ArrayList<? extends A & B> myList4 = new ArrayList<AB>();
//This works but this is a method:
public static <T extends A & B> T someMethod(ArrayList<? extends T> list) {
return null;
}
}
Yes:
class C<T extends A & B> {
ArrayList<T> field;
public <T2 extends A & B> void method() {
ArrayList<T2> localVar;
}
}
It looks a bit odd that you have to define an alias for the generic "type" outside of the scope where you use it but it works. I find it's easiest to see with the method: T2 is never used in the method declaration. It's solely used inside of the method.
It's unfortunate that these inner type limits become part of the public API this way but that's the only way I know to make this work.
If you don't want this, then try an inner, private interface (AB) in your example.
Java does not support multiple inheritance of classes - a class can extend only one single class (although a class can implement multiple interfaces). Hence I believe the
ArrayList<? extends A & B>
doesn't work.
Solution would be create a super type that extends both A & B and then pass the type to your method. Something like
inteface C extends A,B{}
ArrayList<? extends C>

An interface has two type parameters. Can I implement the interface with the two types being the same, such that they are then compatible?

This is an existing interface:
public interface MyInterface<T, U> {
public T foo(U u);
}
I want to implement this interface under the assumption that T and U are the same type. I thought maybe I could leave the type parameters in as they are, and then as long as I only ever instantiate this particular implementation with two of the same type, that it might work:
public class MyOuterClass<A> {
public class MyClass<T, U> implements MyInterface<T, U> {
#Override
public T foo(U u) {
return u; //error here
}
//even though in the only instantiation of MyClass, T and U are the same
private MyClass<A, A> myInstance = new MyClass<A, A>();
}
But, perhaps unsurprisingly, this doesn't work, as types T and U are incompatible.
So then I thought maybe I could change MyClass to specify that its types would always be the same, by changing it to something like MyClass<A, A> implements MyInterface<A, A> or similar, but I get errors saying that T is already defined.
Is there a way to implement MyClass so that its two types will be the same?
(I'm more of a C++ guy than Java, so sorry if I'm missing something fundamental about Java's generic's here.)
Your myclass needs to look like this:
public class MyClass<T> implements MyInterface<T, T> {
#Override
public T foo(T in) {
return in;
}
}
Let's review what your suggested class definition does:
public class MyClass<T, U> implements MyInterface<T, U>
In this code, T and U do two things each:
in the first occurance they define a type variable of your MyClass class
in the second occurance they specify the concrete type of the MyInterface class
Since inside the body of your class T and U are unbounded type variables (i.e. nothing is known about the actual types), they are assumed to be incompatible.
By having only a single type variable in your MyClass you make your assumption explicit: there's only a single type, and I'm using it for both types of the interface.
Last but not least: remember that the compilation of a type is complete once the source is fully handled. In other words: contrary to what C++ does, "instantiation" of a generic type ("template type" or similar in C++; Sorry for my rusty terminology) does not handle. MyClass<Foo> and MyClass<Bar> are the same type, as far as the JVM is concerned (only the compiler actually distinguishes them).
Define a single type parameter for MyClass:
class MyOuterClass<A> {
public class MyClass<T> implements MyInterface<T, T> {
public T foo(T u) {
return u;
}
}
// Need only one 'A' here.
private MyClass<A> myInstance = new MyClass<A>();
}
When you say
public class MyClass<T> implements MyInterface<T, T> {
... you are defining one generic variable for MyClass and you are saying that it fulfills both the roles T and U in MyInterface.

Java Generics: Multiple Inheritance in Bounded Type Parameters <T extends A & I>

I am about to create a factory which creates objects of a certain type T which extends a certain class A and another interface I. However, T must not be known. Here are the minimum declarations:
public class A { }
public interface I { }
This is the factory method:
public class F {
public static <T extends A & I> T newThing() { /*...*/ }
}
This compiles all fine.
When I try to use the method the following works fine:
A $a = F.newThing();
...while this does not:
I $i = F.newThing();
The compiler complains:
Bound mismatch: The generic method newThing() of type F is not applicable for the arguments (). The inferred type I&A is not a valid substitute for the bounded parameter
I can't understand why. It is clearly stated that "newThing returns something of a certain type T which does extend the class A and implement the interface I". When assigning to A everything works (since T extends A) but assigning to I does not (because of what?, clearly the thing returned is both an A and an I)
Also: When returning an object, say B of the type class B extends A implements I, I need to cast it to the return type T, although B matches the bounds:
<T extends A & I> T newThing() {
return (T) new B();
}
However, the compiler does not throw any warnings like UncheckedCast or the like.
Thus my question:
What is going wrong here?
Is there an easy away to achieve the desired behavior (i.e. assigning to a variable of static type A or I), like there is in solving the return-type-problem by casting, in the factory method?
Why does the assignment to A work, while to I does not?
--
EDIT: Here the complete code snippet which totally works using Eclipse 3.7, project set up for JDK 6:
public class F {
public static class A { }
public static interface I { }
private static class B extends A implements I { }
public static <T extends A & I> T newThing() {
return (T) new B();
}
public static void main(String... _) {
A $a = F.newThing();
// I $i = F.newThing();
}
}
EDIT: Here is a complete example with methods and invocation which does work at runtime:
public class F {
public static class A {
int methodA() {
return 7;
}
}
public static interface I {
int methodI();
}
private static class B extends A implements I {
public int methodI() {
return 12;
}
}
public static <T extends A & I> T newThing() {
return (T) new B();
}
public static void main(String... _) {
A $a = F.newThing();
// I $i = F.newThing();
System.out.println($a.methodA());
}
}
As for the second question:
Consider this case:
class B extends A implements I {}
class C extends A implements I {}
Now, the following uses type inference:
<T extends A & I> T newThing() {
return (T) new B();
}
So you could call this:
C c = F.newThing(); //T would be C here
You see that T could be anything that extends A and I you can't just return an instance of B. In the case above the cast could be written as (C)new B(). This would clearly result in an exception and thus the compiler issues a warning: Unchecked cast from B to T - unless you're supressing those warnings.
This doesn't do what you expect it to. T extends A & I indicates that the caller can specify any type that extends A and I, and you'll return it.
I think that one way to explain it is by replacing the type parameter with the actual type.
The parameterized signature of the methods is:
public static <T extends A & B> T newThing(){
return ...;
}
The <T extends A & B> is what is called a type parameter. The compiler would expect that this value is actually substituted with the actual type (called type argument) when you actually use it.
In the case of your method the actual type is decided by means of type inference. That is, <T extends A & B> should be replaced by a real existing type that extends A and implements B.
So, let's say that classes C and D both extends A and implements B, then if your signature were like this:
public static <T extends A & B> T newThing(T obj){
return obj;
}
Then, by type inference, your method would be evaluated as follows:
public static C newThing(C obj){
return obj;
}
if you invoke with newThing(new C()).
And would be as follows
public static D newThing(D obj){
return obj;
}
if you invoke with newThing(new D()).
This would compile just fine!
However, since you are not actually providing any kind of type to validate type inference in your method declaration, then the compiler could never be sure what is the actual type (type argument) of your type parameter <T extends A & B>.
You might expect that the actual type is C, but there may be thousands of different classes that satisfy that criteria. Which of those should the compiler use as the actual type of your type argument?
Let's say that C and D are two classes that extend A and implements B. Which of these two actual types should the compiler use as type argument for your method?
You could have even declared a type argument for which there is not even an existing type that you can use, like saying something that extends Serializable and Closable and Comparable and Appendable.
And perhaps there is not a class in the whole world that satisfies that.
As such, you must understand that the type parameter here is just a requirement for the compiler to validate the actual type that you use, a placeholder for the actual type; and this actual type must exist at the end and the compiler will use it to replace appearances of T. Therefore the actual type (type argument) must be inferable from the context.
Since the compiler cannot tell with certainty which is the actual type that you mean, basically because there is no way to determine that by type inference in this case, then you are forced to cast your type, to ensure the compiler that you know what you are doing.
As such, you could implement your method using type inference like this:
public static <T extends A & B> T newThing(Class<T> t) throws Exception{
return t.newInstance();
}
This way, you would be actually telling the compiler what is the actual type argument to be used.
Take into account that when the bytecodes are generated, the compiler must substitute T for a real type. There is no way to write method in Java like this
public static A & B newThing(){ return ... }
Right?
I hope I have explained myself! This is not simple to explain.
Simplest solution is create an abstract base class that extends and implements whatever class and interfaces you want and return that type. It doesn't matter that you're constraining your return type to extend this base class as you were already constraining the return type to its superclass.
eg.
class C {}
interface I {}
abstract class BaseClass extends C implements I {}
// ^-- this line should never change. All it is telling us that we have created a
// class that combines the methods of C and I, and that concrete sub classes will
// implement the abstract methods of C and I
class X extends BaseClass {}
class Y extends BaseClass {}
public class F {
public static BaseClass newThing() {
return new X();
}
public static void main(String[] args) {
C c = F.newThing();
I i = F.newThing();
}
}

java iterator/iterable subinterface

I have an interface for a variety of classes, all of which should implement Iterator, so I have something like
public interface A extends Iterable<A> { ...otherMethods()... }
For the concrete classes, however, this means I must use
public class B implements A { public Iterator<A> iterator() {...} }
when I'd prefer (or at least, think I'd prefer) to use public Iterator<B> iterator() {...} so that concrete use of the class could have the explicit type (in case I wanted methods that weren't in the interface to be available, or some such. Maybe that should never come up? Or it's poor design if it does?
The flipside is that using the Iterator interface
public interface A extends Iterator<A> { ...otherMethods()... }
the concrete classes compile just fine with
public class B implements A { public B next() {...} }
What gives?
Carl was right, my first answer didn't compile but this seems to. Not sure if it's what you want exactly.
public interface A<T extends A> extends Iterable<T> {
}
public class B implements A<B> {
#Override
public Iterator<B> iterator() {
return null;
}
The concrete class compiles fine because B extends A, and since Java 5 a return type on a subclass can be a subclass of the return type on the superclass.
As for the generic, I have hit the same wall, and you have two options that I know of.
One is to paramaterize A:
public interface A<T extends A> extends Iterable<T>
then:
public class B implements A<B>
However, that has a disadvantage that you will need to give a parameter of A, instead of having it fixed, even if you want A:
private class NoOneSees implements A<A>
As to the question of if you actually want Iterator<B>, in the case of an Iterable, most likely that is preferable, and considering that these are interfaces, the need to redeclare the parameter is probably reasonable. It gets a little more complicated if you start inheriting concrete classes, and for things that have meaning other than an Iterable, where you may want covariance. For example:
public interface Blah<T> {
void blah(T param);
}
public class Super implements Blah<Super> {
public void blah(Super param) {}
}
public class Sub extends Super {
public void blah(Super param) {}
//Here you have to go with Super because Super is not paramaterized
//to allow a Sub here and still be overriding the method.
}
Similarly for covariance, you can't declare a variable of type Iterator<A> and then assign an Iterator<B> in it, even if B extends A.
The other option is live with the fact that further implementation/subclasses will still reference A.
The other answers have the right gist - but you'll get the right mechanics by declaring the generic type as
A<T extends A<T>>
This forces a class to return an iterator that is of its own type or lower - so you would be able to declare
class B implements A<B>
but not
class B implements A<A>
which I suspect is closer to what you want (i.e. implementations must return iterators over themselves, rather than simply over As).
Note that your experiences with Iterator vs Iterable stem from the lack of covariance of generic types; an instance of B is an A, but an Iterator<B> is not an Iterator<A>.
I guess this is what you want:
public interface A<T extends A<?>> extends Iterable<T>
public class B implements A<B> {
public Iterator<B> iterator() {...}
}
Your design decisions are your own, but I can't think of any reason for EVERY class in a design to implement Iterable. There must be some kind of thing that is contained in a collection but isn't actually a collection itself. I would take a long hard look at the fundamental design. Maybe some iterables will want to return iterators of things that are not related to themselves.

Categories

Resources