Java泛型类型不匹配

时间:2011-04-19 14:56:02

标签: java generics

我有一个抽象类定义为:

public abstract class TCV<T extends MF> {
    public Map<String, MVR<T>> operation() {
        ...
    }
}

主要代码:

TCV<? extends MF> o = new TCVConcrete();
Map<String, MVR< ? extends MF>> map = o.operation();

eclipse出错:

Type mismatch: cannot convert from Map<String,MVR<capture#5-of ? extends MF>> to Map<String,MVR<? extends MF>>

修改

public class TCVConcrete extends TCV<MFV2> {
}

public class MFV2 extends MF {
}

4 个答案:

答案 0 :(得分:4)

主要问题是因为您无法将Box<Tiger>投射到Box<Cat>,为什么?您可以将其视为,

Box<Cat>可以包含猫和老虎,但Box<Tiger>只能包含老虎。如果您将Box<Tiger>投射到Box<Cat>,之后又会将BlackCat投放到Box<Tiger>

Box<Cat> catBox = tigerBox;
catBox.throwHere(new BlackCat());

然后,tigerBox已损坏。

让我将你的问题改为:

public abstract class Company<T extends Cat> {
    public Box<T> getFavBox() {
        // ...
    }
    public Set<Box<T>> getBoxes() {
        // ...
    }
}

Company<? extends Cat> o = new ETCatCompany();
Box<? extends Cat> boxes = o.getFavBox();        // ok
Set<Box<? extends Cat>> boxes = o.getBoxes();    // error

如你所见,o.getFavBox()会有效,但o.getBoxes()不行,为什么?

因为,你不能将任何具体的猫扔进Box<? extends Cat>,这可能会破坏未知的盒子。但是,您可以将Box<BlackCat>投入Set<Box<? extends Cat>>,这可能会导致Set<Box<Tiger>>损坏。

或者,你可以认为:

Cat ^ Tiger => Cat
Box<Cat> ^ BigBox<Cat> => Box<Cat>
Box<Cat> ^ Box<Tiger> => Box<? extends Cat>
Box<Cat> ^ BigBox<Tiger>
    => (Box<Cat> ^ BigBox<Cat>) ^ (BigBox<Cat> ^ BigBox<Tiger>)
    => Box<Cat> ^ BigBox<? extends Cat>
    => Box<? extends Cat> ^ BigBox<? extends Cat>
    => Box<? extends Cat>

Set<Box<Cat>> ^ Set<BigBox<Cat>> => Set<? extends Box<Cat>>
Set<Box<Cat>> ^ Set<Box<Tiger>> => Set<? extends Box<? extends Cat>>
Set<Box<Cat>> ^ Set<BigBox<Tiger>> => Set<? extends Box<? extends Cat>>

? extends Cat ^ ? extends Tiger => ? extends Cat
Box<? extends Cat> ^ BigBox<? extends Cat> => Box<? extends Cat>
Box<? extends Cat> ^ Box<? extends Tiger> 
    => ? extends Box<? extends (? extends Cat)>
    => ? extends Box<? extends Cat>

Set<Box<? extends Cat>> ^ Set<BigBox<? extends Cat>> 
    => Set<? extends Box<? extends Cat>>

Set<Box<? extends Cat>> ^ Set<Box<? extends Tiger>>     // You are here.
    => Set<? extends Box<? extends Cat>>

Set<Box<? extends Cat>> ^ Set<BigBox<? extends Tiger>> 
    => Set<? extends Box<? extends Cat>>

或者更有可能的是,给几个operation()调用:

Map<String, MVR<?1 extends MF>> x1 = o.operation();
Map<String, MVR<?2 extends MF>> x2 = o.operation();
...
Map<String, MVR<?n extends MF>> x2 = o.operation();

那么,共同类型是什么?

x1 ^ x2 ^ ... ^ xn
    => Map<String, MVR<?1 extends MF>> ^ Map<String, MVR<?2 extends MF>> ^ ...
    => Map<String, ? extends MVR<? extends MF>> ^ ...
    ...
    => Map<String, ? extends MVR<? extends MF>>

嗯,这两个通配符肯定没问题,它是关于数学归纳的......

答案 1 :(得分:2)

这里的问题是你有两个不同的通用定义可能是相同的:

TCV<? extends MF> o = new TCVConcrete();
    ^^^^^^^^^^^^
Map<String, MVR< ? extends MF>> map = o.operation();
                ^^^^^^^^^^^^^^

虽然这两个可以指向相同类型,但它们也可以指向MF的两个不同子类型。编译器不喜欢这样。

您可以使用专用方法中的类型变量来解决这个问题 这应该有效:

public void <T extends MF> doSomething(){
    TCV<T> o = new TCVConcrete();
    Map<String, MVR<T>> map = o.operation();
}

答案 2 :(得分:0)

泛型系统无法理解两行中指示的泛型类型(当应用于具体实现时)实际上在编译器执行其业务时引用相同的具体类型。

TCV<? extends MF> o = new TCVConcrete();
Map<String, MVR< ? extends MF>> map = o.operation();

Serializable的简单情况下,有许多类实现Serializable,因此一个语句可能意味着一个类,另一个语句可能意味着另一个,因此这将无法编译。您需要在文件的顶部创建一个类型范围,然后对两个行使用相同的类型,或者实现MF的子类并将其用于两个行,而不是将其保留为浮动泛型类型。

答案 3 :(得分:0)

问题是你用的是两个?通配符,基本上说“MF或MF的一些未指定的子类”。但这可能意味着MF的两个不同的子类;这就是分配类型不匹配的原因。

你可能想要的是根本不使用通配符。这应该有效:

TCV<MF> o = new TCVConcrete();
Map<String, MVR<MF>> map = o.operation();