I'm having trouble understanding why I can use bounded wildcards like this, if I can't (seem to) make any (genericly-typed) use of it.
If I have a wildcard field in a class, I can't use any of the methods with generic parameters of the implemented interface (unless I supply null
as the argument).
class SomeClass {}
class DerivedClass extends SomeClass {}
interface IInterf<T extends SomeClass> {
T returnsT();
void paramT(T parm);
T paramAndReturnT(T parm);
int nonGenericMethod(int x);
}
class Impl {
protected IInterf<?> field; //this is bound to <extends SomeClass>
//- it's implied by the definition
// of IInterf which is bound
// but what's the point?
public Impl(IInterf<? extends SomeClass> var){
field = var;
}
public void doSmth(){
SomeClass sc = field.returnsT(); //works
field.paramT(new SomeClass());
//error: method paramT in interface IInterf<T> cannot be applied to given types;
//required: CAP#1
//found: SomeClass
//reason: actual argument SomeClass cannot be converted to CAP#1 by method invocation conversion
//where T is a type-variable:
// T extends SomeClass declared in interface IInterf
//where CAP#1 is a fresh type-variable:
// CAP#1 extends SomeClass from capture of ?
field.paramT(null); //works
SomeClass sc2 = field.paramAndReturnT(new DerivedClass());
//error: method paramAndReturnT in interface IInterf<T> cannot be applied to given types;
// SomeClass sc2 = field.paramAndReturnT(new DerivedClass()); //required: CAP#1
//found: DerivedClass
//reason: actual argument DerivedClass cannot be converted to CAP#1 by method invocation conversion
//where T is a type-variable:
// T extends SomeClass declared in interface IInterf
//where CAP#1 is a fresh type-variable:
// CAP#1 extends SomeClass from capture of ?
//
int x = field.nonGenericMethod(5); //obviously works.
}
}
FWIW, I couldn't convince the C# compiler to accept something similar.
Am I missing something?
When you declare field
as
protected IInterf<?> field;
the ?
stands for an unknown class that extends SomeClass
. Think of it not asa wildcard but as a particular class deriving SomeClass
but anonymous.
If you now try to call
field.paramT(new SomeClass());
this fails because a SomeClass
instance is not compatible to what the ?
is standing for, namely the anonymous class that extends SomeClass
.
There is no problem to use null
, this is compatible with any class.
Exactly the same happens with
SomeClass sc2 = field.paramAndReturnT(new DerivedClass());
You are right, you can't use these methods. Often, you don't need these methods (for example, you add something <? extends T>
to a collection <T>
. It makes sense to use them if you don't need more information. If you need to call these methods, you can't use wildcards. Instead, you could do <T extends SomeClass>
.
You're trying to use generics/wildcards where they are not needed. Instead, either of the following will work:
1) Define the interface so that it accepts any class, and limit the types when using the interface:
interface IInterf<T> {}
protected IInterf<SomeClass> field;
2) Define the interface so that it accepts classes that extend SomeClass
, and use the interface without specifying extra type information:
interface IInterf<T extends SomeClass> {}
protected IInterf field;
As for why the wildcard does not work: ? extends SomeClass
? extends SomeClass
means an unknown subtype of SomeClass
. Since we don't know what the type is, we don't know if it is a supertype of SomeClass
(or DerivedClass
in the second method call); it might or might not be such a supertype, so it isn't safe to pass SomeClass
(or DerivedClass
). (from the Java Wildcards documentation )
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.