Reputation: 1440
I have some interfaces (and for completeness two dummy classes, so you may copy the code into your ide)
public interface ItfA
{
String getA();
}
public interface ItfB
{
String getB();
}
public class MyClassAdapter
{
public Object getValue(Object bean)
{
return null; // override to do something useful
}
}
public class MyClass
{
public MyClass(MyClassAdapter mca)
{
// do something useful with it
}
}
And I have some functions using these as parameters (looks a bit weird, but that's how I have to use them (I can't change the MyClassAdapter
)) ...
public <T extends ItfA> MyClass getMyClass(final Class<T> itf)
{
return new MyClass(new MyClassAdapter()
{
@Override
public Object getValue(Object bean)
{
return itf.cast(bean).getA();
}
}
);
}
So I can call this getMyClass
only with classes implementing interface ItfA
- otherwise the compiler will complain.
Alternatively I can rewrite this method without the named generic type T as ...
public MyClass getMyClass2(final Class<? extends ItfA> itf)
{
return new MyClass(new MyClassAdapter()
{
@Override
public Object getValue(Object bean)
{
return itf.cast(bean).getA();
}
}
);
}
In some cases I need classes as parameters that implement more than one interface - this will work:
public <T extends ItfA & ItfB> MyClass getMyOtherClass(final Class<T> itf)
{
return new MyClass(new MyClassAdapter()
{
@Override
public Object getValue(Object bean)
{
return itf.cast(bean).getA() + itf.cast(bean).getB();
}
}
);
}
but this one doesn't work
public MyClass getMyOtherClass2(final Class<? extends ItfA & ItfB> itf)
{
return new MyClass(new MyClassAdapter()
{
@Override
public Object getValue(Object bean)
{
return itf.cast(bean).getA() + itf.cast(bean).getB();
}
}
);
}
I don't get the difference between these two kinds of generic parameters (<T extends ItfA>
before the method name and using Class<T>
in the parameters opposed to using Class<? extends ItfA>
in the parameters) - why do both types work with one interface, and why does one work with two interfaces, but the other one doesn't.
Any hints? To me, the second variant is a bit more readable, so I'd prefer that, but I don't get it to work with multiple interfaces ...
Upvotes: 0
Views: 48
Reputation: 43661
Unlike TypeParameter, TypeArgument can't have several bounds, so <? extends ItfA & ItfB>
is not valid.
Here's my guess on why it is so.
I think the reason is that TypeArgument needs to be specific to be useful. For instance in case of Class<T>
the method cast
returns T
, you should be able to declare a variable of that type and assign the result to it.
TypeArgument can be:
Cases 1-4 are not problematic, there you always have some specific type or type variable.
In case of the Wildcard we have WildcardBounds for instance <? extends IntfA>
.
If you allow just one upper bound, then you have something specific for T
. In case of Class<? extends IntfA>
you can assume that cast
returns InfA
.
If you allow more that one upper bound <? extends ItfA & ItfB>
then the question is, what could you use for T
then? Since you in general case you don't have any specific type for T
, the best you can do is Object
which is not very useful.
I think this is the reason language authors did not allo multiple upper bounds for wildcard type arguments.
Upvotes: 1