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



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

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

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

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

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

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

您的copyFrom方法被声明为

public void copyFrom(T source);

这意味着目标中对象的泛型类型自变量必须与源的泛型类型参数相同,即两者都必须是某种类型的T

当然,如果使用像?这样的通配符类型,编译器就无法判断?在源和目标中是否属于同一类型T,毕竟它可能不同,例如。

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

上面的CCD_ 9表示两种不同类型的CopyInterface<Foo>和CCD_。因此,正如你所看到的,当你使用?时,你会丢失类型信息,而这些信息后来编译器无法做出重要的决定,你会得到这些编译器错误。

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

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

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

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

但是,只要您在这里使用通配符类型,我怀疑您是否能够使其工作。

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

我很清楚,编译器无法检查源和目标是否属于同一类型。但我想我可以用显式类型转换而不是原始类型来解决这个问题。所以我现在找到了以下解决方案,它似乎有效:

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

最新更新