Call method from a generic wildcard reference
the following code boils down to the main question for the question:
public class GenericTest
{
private interface CopyInterface<T extends CopyInterface<T>>
{
public void copyFrom(T source);
}
public void testMethod()
{
CopyInterface<?> target;
CopyInterface<?> source;
target.copyFrom(source);
}
}
This results in the following compiler error message:
The copyFrom (capture # 1-of?) Method of type GenericTest.CopyInterface is not applicable for arguments (GenericTest.CopyInterface). GenericTest.java/ACAF/src/de/tmasoft/acaftest/attributes line 14 Java problem
When I use a raw type for the target variable, I just get a raw type warning. Is there a way to get this compiled without using raw-type?
source to share
The problem is that your source type is incompatible with the target type, but this requires your method declaration.
Your method is copyFrom
declared as
public void copyFrom(T source);
This means that the generic type argument for the object in the target must be the same as the source, that is, both must be of a specific type T
.
Of course, if you use a type wildcard ?
, the compiler cannot tell if ?
the type is the same T
in both the source and the target, in the end it might be different, for example.
CopyInterface<?> target = new Foo();
CopyInterface<?> source = new Bar();
The above ?
represents two different types of CopyInterface<Foo>
and CopyInterface<Bar>
. So, as you can see, when you use ?
, you lose type information that later prevents the compiler from making important decisions, and you get these compiler errors.
Returning to the method copyFrom
, in such a case, the compiler cannot know whether it is of the ?
type T
that the method expects copyFrom(T source)
, hence your compiler error.
You wouldn't have this problem if both sources and targets were of the same type.
For example, if you had an implementation of your interface like this:
class Foo implements CopyInterface<Foo> {
@Override public void copyFrom(Foo source){}
}
Then you won't have a problem with this:
Foo target = new Foo();
Foo source = new Foo();
target.copyFrom(source);
In this case, T
there Foo
is in both source and target, and it is compatible with your method signature.
Since it looks like you are only reading from source, you can also relax the rules in your interface by declaring it like this:
interface CopyInterface<T extends CopyInterface<T>> {
void copyFrom(CopyInterface<? extends T> source);
}
Then your implementation might look like
class Foo implements CopyInterface<Foo> {
@Override public void copyFrom(CopyInterface<? extends Foo> source){}
}
Then you could do
CopyInterface<Foo> target = new Foo();
CopyInterface<Foo> source = new Foo();
target.copyFrom(source);
But as long as you're using wildcard types here, I doubt you can manage to get it to work.
source to share
Parameter estimation is CopyInterface
useless. CopyInterface
it doesn't matter where you can copy it from. It is testMethod
that that takes care of how it is used copyFrom
. Therefore, you want to make a testMethod()
generic method that puts constraints on what its type parameter should support. (Of course, in a real-world example, it T
must be used in a parameter or return type testMethod
for it to make sense.)
private interface CopyInterface<T>
{
public void copyFrom(T source);
}
public <T extends CopyInterface<? super T>> void testMethod()
{
T target;
T source;
target.copyFrom(source);
}
source to share
It is clear to me that the compiler cannot check if the source and target are of the same type. But I thought I could solve it with an explicit application and not with raw types. So I found now the following solution, which seems to work:
public class GenericTest
{
private interface CopyInterface<T extends CopyInterface<?>>
{
public void copyFrom(T source);
}
private class A implements CopyInterface<A>
{
@Override
public void copyFrom(A source)
{}
}
public static void copy(CopyInterface<?> source,
CopyInterface<? super CopyInterface<?>> target)
{
target.copyFrom(source);
}
@SuppressWarnings("unchecked")
public void testMethod()
{
CopyInterface<?> target = new A();
CopyInterface<?> source = new A();
((CopyInterface<? super CopyInterface<?>>) target).copyFrom(source);
copy(source, (CopyInterface<? super CopyInterface<?>>) target);
}
}
But I must admit that I don't quite understand the difference between
interface CopyInterface<T extends CopyInterface<?>>
and
interface CopyInterface<T extends CopyInterface<T>>
source to share