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

3
下面的代码已经简化成了必要的部分以便于提问:
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 line 14 Java Problem

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


这是指你使用了<T extends CopyInterface<T>>,而不是例如<T extends CopyInterface<?>><T extends CopyInterface<K>>吗? - Nicolas Mattia
4个回答

4

您需要将testMethod()方法泛型化,并声明sourcetarget是相同类型的:

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

2

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

你的copyFrom方法被声明为

public void copyFrom(T source);

这意味着目标对象中的泛型类型参数必须和源对象相同,都必须是某个类型 T

当然,如果你使用通配符类型,比如 ?,编译器就无法确定在源对象和目标对象中的 ? 是否是相同的类型 T,因为它们可能是不同的类型。

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

上面的?代表了两种不同类型的CopyInterface<Foo>CopyInterface<Bar>。因此,当你使用?时,你会失去类型信息,编译器后来就无法使用这些信息做出重要决策,从而导致编译错误。
回到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);

但只要在这里使用通配符类型,我怀疑你能否成功实现它。


1
< p > CopyInterface 的参数限制是无用的。 CopyInterface 不关心可以从哪些地方复制。它是 testMethod 关心如何使用 copyFrom。因此,您需要使 testMethod() 成为通用方法,这会对其类型参数施加限制。(当然,在真实示例中,必须在 testMethod 的参数或返回类型中使用 T 才有意义。)< /p >
private interface CopyInterface<T>
{
    public void copyFrom(T source);
}

public <T extends CopyInterface<? super T>> void testMethod()
{
    T target;
    T source;
    target.copyFrom(source);
}

这是显而易见的。实际上,复制对象的方法使用两个 List<CopyInterface<?>> 列表。这些列表可能包含不同具体类的实例。因此无法指定具体类型。 - thmayr
@thmayr:如果您的情况不同,请在问题中说明;否则,无法给出适当的答案。如果列表是一个包含不同具体类的异构列表,则当前声明的两个元素之间使用copyFrom方法没有安全的方法。如果列表是同质的,即它随时保存相同具体类的元素,但这个类在编译时是未知的,则应该在泛型函数内部使用List<T>,其中T是那个特定的具体类。 - newacct

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接