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?

+3


source to share


4 answers


You have to make your testMethod()

generic and declare that source

both target

are of the same type:



public <T extends CopyInterface<T>> void testMethod() {
    T target = ...; //initialize the variable
    T source = ...; //initialize the variable
    target.copyFrom(source);
}

      

+4


source


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.

+2


source


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);
}

      

+1


source


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>>

      

0


source







All Articles