Are these two (valid) generic bounds:
<T extends Enum<T> & MyInterface>
<T extends Enum<? extends MyInterface>>
the same?
Suppose I have an interface
interface MyInterface {
void someMethod();
}
And some enums that implement it:
enum MyEnumA implements MyInterface {
A, B, C;
public void someMethod() {}
}
enum MyEnumB implements MyInterface {
X, Y, Z;
public void someMethod() {}
}
And I want to require that an implementation uses not only a MyInterface
but also that it is an enum. The "standard" way is by an intersection bound:
static class MyIntersectionClass<T extends Enum<T> & MyInterface> {
void use(T t) {}
}
But I've discovered that this also works:
static class MyWildcardClass<T extends Enum<? extends MyInterface>> {
void use(T t) {}
}
With the above, this compiles:
public static void main(String[] args) throws Exception {
MyIntersectionClass<MyEnumA> a = new MyIntersectionClass<MyEnumA>();
a.use(MyEnumA.A);
MyWildcardClass<MyEnumB> b = new MyWildcardClass<MyEnumB>();
b.use(MyEnumB.X);
}
And the bound works as and intended and required by above for both cases.
Is there a difference between these two bounds, if so what, and is one "better" than the other?
In this specific case there is no difference because Enums formal type parameter is effectively the self type. This is because one can not inherit from Enum like so:
class MyEnumA extends Enum<MyEnum2> {}
class MyEnumB implements MyInterface {}
So yes, semantically they're the same bound, but only because it's Enum.
As others have pointed out, both syntaxes achieve the same bounds - and only because of the special case of enums, where we know the T
in Enum<T>
must be the immediately extending enum
type. So in restricting what T
can be resolved to, there's no difference.
There is a difference in the possible usage of instances of T
, but it's probably such a nuance that it's irrelevant. Consider that the following statement compiles in MyIntersectionClass.use
but not MyWildcardClass.use
:
T t2 = t.getDeclaringClass().newInstance();
Only these will compile in the latter:
MyInterface t2 = t.getDeclaringClass().newInstance();
Enum<? extends MyInterface> t3 = t.getDeclaringClass().newInstance();
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