关于java:无法使用泛型转换为非特定的嵌套类型

Can't cast to to unspecific nested type with generics

我有两个具有嵌套泛型的类。有没有办法摆脱

类型不匹配:无法从Msg>转换为Msg>错误?在上一个任务中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Value<V> {
    V   val;

    public Value(V val) {
        this.val = val;
    }
    @Override
    public String toString() {
        return"" + val;
    }
}

public class Msg<T> {

    T holder;

    public Msg( T holder) {
        this.holder = holder ;
    }
    public String toString() {
        return"" + holder;
    }

    public static void main(String[] args) {
        Msg<Value<String>>strMsg = new Msg(new Value<String>("abc"));
        // This is OK
        Msg<?>objMsg = strMsg;
        // Type mismatch: cannot convert from Msg<Value<String>> to Msg<Value<?>>  
        Msg<Value<?>>objMsg = strMsg;
    }
}


使用以下内容:

1
Msg<? extends Value<?>> someMsg = strMsg;

问题是Msg> objMsg中的?不能捕获转换。它不是某种类型的"Value"的"Msg"。它是"任何类型的ValueMsg"。

这也解释了为什么在声明更改的同时,我还将变量重命名为someMsgValue不能只是一个Object而已。它必须属于某种类型(本例中的String)。

更一般的例子

让我们考虑一个更通用的List>示例。与原始场景类似,List>无法捕获转换List>

1
2
3
4
5
6
7
    List<List<Integer>> lolInt = null;

    List<List<?>> lolAnything = lolInt;         // DOES NOT COMPILE!!!
    // a list of"lists of anything"

    List<? extends List<?>> lolSomething = lolInt;   // compiles fine!
    // a list of"lists of something"

另一种方法是:

  • Java泛型是类型不变量。
  • 有一个从IntegerNumber的转换,但是List<Integer>不是List<Number>的转换。
    • 类似地,List可以被List转换,但List<List>不是List<List>的。
  • 使用有界通配符,ListNumber>可以捕获转换List<Integer>的EDOCX1。
    • 同样,一个ListList>可以捕获一个List<List>的转换。

一些?可以捕获,而另一些则不能解释以下片段:

1
2
3
4
    List<List<?>> lolAnything = new ArrayList<List<?>>(); // compiles fine!

    List<?> listSomething = new ArrayList<?>(); // DOES NOT COMPILE!!!
        // cannot instantiate wildcard type with new!

相关问题

  • 泛型方法上的多个通配符使Java编译器(和ME!)非常困惑
    • 对这个问题进行了很长很详细的探讨
  • Java通用EDCOX1〔42〕
  • 有什么简单的方法来解释为什么我不能做List animals = new ArrayList()
  • 有什么区别?

也见

  • Java泛型教程
    • 泛型和子类型通配符使用通配符更有趣
  • Angelika Langer的Java泛型常见问题解答
    • 什么是有界通配符?
    • 在泛型类型的实例化之间存在哪些超级子类型关系?


我的回答和另一个类似,但希望更清楚。

1
2
3
List<List<?>> is a list of (lists of anything).

List<List<String>> is a list of (lists of strings).

后者无法转换为前者,因为这样做将允许您向列表中添加一个列表>,该列表显然会被破坏。

请注意,如果用没有的类型替换列表,则此规则不会更改。添加。Java将需要声明站点协方差和/或逆反(例如C语言的iQuestaby < Ext T>或斯卡拉的列表[+A])。Java只有使用站点协方差和逆变(?)扩展X,?超级X)。


尽管泛型类型参数包含通配符,但它本身不是通配符。当分配给具有非通配符泛型类型T的变量(Msg时,被分配的对象必须正好具有T作为其泛型类型(包括T的所有泛型类型参数、通配符和非通配符)。在你的例子中,TValue,它与Value的类型不同。

由于Value可分配给Value,您可以做的是使用通配符类型:

1
Msg<? extends Value<?>> a = new Msg<Value<String>>();

不是一个直接的答案,但我强烈建议您阅读:http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf以更好地理解泛型。


ilmtitan有一个很好的解决方案,如果您不想使类特定于值,那么此时您也可以使用基类型而不是泛型,因为您将关闭一个安全功能,但有一种方法。您甚至可以传递一个参数来使这个方法更通用,但关键是"@suppresswarnings"。

1
2
3
4
5
@SuppressWarnings("unchecked")
Msg<Value<?>> convert()
{
    return (Msg<Value<?>>) this;
}