I know there's all sorts of counter-intuitive properties of Java's generic types. Here's one in particular that I don't understand, and which I'm hoping someone can explain to me. When specifying a type parameter for a class or interface, you can bound it so that it must implement multiple interfaces with public class Foo<T extends InterfaceA & InterfaceB>
. However, if you're instantiating an actual object, this doesn't work anymore. List<? extends InterfaceA>
is fine, but List<? extends InterfaceA & InterfaceB>
fails to compile. Consider the following complete snippet:
import java.util.List;
public class Test {
static interface A {
public int getSomething();
}
static interface B {
public int getSomethingElse();
}
static class AandB implements A, B {
public int getSomething() { return 1; }
public int getSomethingElse() { return 2; }
}
// Notice the multiple bounds here. This works.
static class AandBList<T extends A & B> {
List<T> list;
public List<T> getList() { return list; }
}
public static void main(String [] args) {
AandBList<AandB> foo = new AandBList<AandB>(); // This works fine!
foo.getList().add(new AandB());
List<? extends A> bar = new LinkedList<AandB>(); // This is fine too
// This last one fails to compile!
List<? extends A & B> foobar = new LinkedList<AandB>();
}
}
It seems the semantics of bar
should be well-defined -- I can't think of any loss of type-safety by allowing an intersection of two types rather than just one. I'm sure there's an explanation though. Does anyone know what it is?
&
character is the standard way to denote multiple bounds. "class AandBList<T extends A & B>
" is just how the language works, although I agree it would be more intuitive to use<T extends A, B>
to matchpublic interface A extends C, D
. And, in generic type bounds, you useextends
regardless of whether it's an interface or a class. Confusing, I know, but that's the way it currently is. – Sealed