从通用通配符引用调用方法

时间:2015-04-27 11:04:35

标签: java generics

以下代码简化为问题的基本要点:

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

这会导致以下编译器错误消息:

GenericTest.CopyInterface类型中的copyFrom(capture#1-of?)方法不适用于参数(GenericTest.CopyInterface)GenericTest.java / ACAF / src / de / tmasoft / acaftest / attributes第14行Java问题

当我使用原始类型作为变量目标时,我只得到一个原始类型警告。有没有办法在不使用原始类型的情况下编译?

4 个答案:

答案 0 :(得分:4)

您必须使glm通用并声明testMethod()source属于同一类型:

target

答案 1 :(得分:2)

问题是您的源类型与目标类型的类型不兼容,但这是您的方法声明所需要的。

您的copyFrom方法被声明为

public void copyFrom(T source);

这意味着target中对象的泛型类型参数必须与source的相同,即两者必须是某种类型T

当然,如果您使用类似?的通配符类型,编译器无法判断?在源和目标中是否具有相同类型T,例如,它可能会有所不同。

CopyInterface<?> target = new Foo();
CopyInterface<?> source = new Bar();

以上?代表两种不同的类型CopyInterface<Foo>CopyInterface<Bar>。因此,正如您所看到的,当您使用?时,您会丢失类型信息,以后编译器无法做出重要决策并且您会收到编译器错误。

回到copyFrom方法,在这种情况下,编译器无法知道?是否对应于方法T所期望的类型copyFrom(T source),因此你的编译器错误。

如果源和目标属于同一类型,则不会出现此问题。

例如,如果您的接口实现如下:

class Foo implements CopyInterface<Foo> {
 @Override public void copyFrom(Foo source){}
}

然后你不会有这样的问题:

Foo target = new Foo();
Foo source = new Foo();
target.copyFrom(source);

在这种情况下,T在源和目标中都是Foo,这与您的方法的签名兼容。

由于您看起来只是从源代码中读取,因此您还可以通过声明如下来放宽界面中的规则:

interface CopyInterface<T extends CopyInterface<T>> {
   void copyFrom(CopyInterface<? extends T> source);
}

然后您的实现可能看起来像

class Foo implements CopyInterface<Foo> {
   @Override public void copyFrom(CopyInterface<? extends Foo> source){}
}

然后你可以做

CopyInterface<Foo> target = new Foo();
CopyInterface<Foo> source = new Foo();
target.copyFrom(source);

但是只要你在这里使用通配符类型,我怀疑你是否可以设法让它工作。

答案 2 :(得分:1)

CopyInterface参数的界限是无用的。 CopyInterface并不关心可以复制的内容。 testMethod关注copyFrom的使用方式testMethod()。所以你想让T成为一个泛型方法,它对类型参数必须支持的内容施加限制。 (当然,在一个真实的例子中,testMethod必须在private interface CopyInterface<T> { public void copyFrom(T source); } public <T extends CopyInterface<? super T>> void testMethod() { T target; T source; target.copyFrom(source); } 的参数或返回类型中使用才能使其有意义。)

int value = array[1]*256 + array[0];

答案 3 :(得分:0)

对我来说很清楚,编译器无法检查源和目标是否属于同一类型。但我认为我可以通过显式转换而不是原始类型来解决它。所以我现在发现了以下解决方案,它似乎有效:

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

但我必须承认,我并不完全理解

之间的区别
interface CopyInterface<T extends CopyInterface<?>> 

interface CopyInterface<T extends CopyInterface<T>>