Javagenerics编译器错误

当用Java做一些不太奇特的东西时,我遇到了一个带有generics的错误,我无法理解为什么它不起作用。 代码是:

package test; import java.util.*; public class TestClass { public static class A extends C{} public static class B extends C{} public static class C{} public static class D{} public static class E{} public static void main(String args[]){ E<D> a = new E<D>(); E<D> b = new E<D>(); E<D> c = new E<D>(); E<D> d = new E<D>(); D e = new D(); D f = new D(); D g = new D(); } } 

编译时得到的错误是:

 test / TestClass.java:11:不兼容的类型
发现:test.TestClass.E>
 required:test.TestClass.E>
       E> a = new E>();
                             ^
 test / TestClass.java:12:不兼容的类型
发现:test.TestClass.E>
 required:test.TestClass.E>
       E> b = new E>();
                                  ^
 test / TestClass.java:13:不兼容的类型
发现:test.TestClass.E>
 required:test.TestClass.E>
       E> c = new E>();
                             ^
 test / TestClass.java:14:不兼容的类型
发现:test.TestClass.E>
 required:test.TestClass.E>
       E> d = new E>();
                           ^
 4个错误

如果E<D> 发现了E<D> ,那肯定会匹配E<D> E<D> ,对吧? 还是我错过了什么?

也许这会帮助你理解:

  ArrayList aList = new ArrayList(); 

这不会编译任何类似的错误。

编辑:咨询: http : //www.ibm.com/developerworks/java/library/j-jtp01255.html

这与之前发布的情况基本相同。 基本上,在generics案例中,您永远不会被允许这样做:

想想这个例子:

 ArrayList alist = new ArrayList(); 

这不会编译,因为它不是类型安全的。 您可以添加字符串aList。 您试图将保证为Numbers但可以是任何Number的对象列表分配给仅保证包含对象但可以是任何对象的列表。 如果编译器允许这种情况,它将放宽对允许哪些类型的对象进入列表的限制。 这就是你必须使用通配符?的原因:

 ArrayList alist = new ArrayList(); 

编译器ArrayList ArrayList ,意思是“某个特定类型的ArrayList”? 我不知道,但我知道扩展了Object。这个ArrayList保证只包含这个未知的元素’?’ 类型,因此只包含对象“。 在这种情况下,编译器将不允许您执行alist.add(2)。 为什么会这样,因为编译器不知道列表元素的类型,并且不能保证允许您将Integer对象插入其中。

你认为D DD的超类型D D 。 但是, List> List>不是List>的子类型List> List> ,你应该使用List> List> List>

你的情况基本上相当于

 ArrayList> alist = new ArrayList>(); 

你有与上面相同的问题,右边的列表只能包含类型为参数为C的D类对象,并且你试图将它分配给一个列表(在左侧)可以包含类的对象D的类型参数可以是任何对象。

因此,如果编译器允许您的代码不是类型安全的,则以下操作将失败。

 ArrayList> alist = new ArrayList>(); //< not type safe alist.add(new D); //< oops 

简而言之,您的具体示例需要以下内容:

 // type parameter of left hand side is ? extends subtype List> b = Arrays.asList(new D(), new D()); // type parameter of left hand side is identical List> b = Arrays.asList(new D(), new D()); // type parameter of left hand side is ? extends subtype List> c = Arrays.asList(new D()); // type parameter of left hand side is identical List> c = Arrays.asList(new D()); 

希望这可以帮助。

检查Arrays.asList调用返回的对象的类型。 我它会返回一个List >对象,它不能转换为List >。

指定类型的上限,这意味着类型必须从C扩展。 显然更通用,因此它不兼容。

想想这个用例。 通过指定上限,您希望实现某个最小接口。 假设您在C中声明了一个doIt()方法。任何扩展C的类都将具有该方法,但不是每个扩展Object的类(这是Java中的每个类)。

当使用非通配符generics类型T分配给变量( E )时,所分配的对象必须具有与其generics类型完全相同的T (包括T所有generics类型参数,通配符和非通配符)。 在你的情况下, TD ,它与D类型不同D D

你可以做什么,因为D可分配给D D ,是使用通配符类型:

 E> a = new E(); 

这比那更糟糕。 你甚至不能这样做:

 List> lDQ = Arrays.asList(new D()); 

如果您按以下方式更改程序则更清楚:

 List> a = Arrays.asList(new D(), new D()); //compiles List> b = a; //error 

基本上,你将b声明为可以接受一般内容( D< anything > )的东西 ,但是你分配给它的列表只接受更具体的内容( D< 最近的A和B的公共超类 > )。

b声明为List> List>暗示你可以说b.add(new D()) ,但它实际上是一个List> List> ,所以你不能。

您不能在generics-parameter中inheritance。 假设您有以下参考:

 List a; List b; 

现在你指定两个相同的列表:a = b;

如果某些代码执行以下操作:

 a.add(new Integer(1)); 

如果有人执行以下操作会发生什么:

 String s = b.get(0); 

你会得到一个字符串列表的整数。 那应该不行。 这就是List和List不兼容的原因,尽管可以将String分配给Object-reference。 generics不适用于inheritance。

那就是List> List>基本上定义了一个新类, List> List> 。 即使c扩展Object并不意味着List> List> extends List> List> ,这将是分配工作所需要的。

虽然本系列文章是针对.NET平台编写的,但对Javagenerics问题的描述仍然适用

如果我们扩展您的示例,我认为这将更加清晰。 让我们在E中加入一些function,并详细说明main方法的第一行:

 public static class E{ private final T thing; public void setThing(T thing) { this.thing = thing; } public T getThing() { return thing; } } public static void main(String[] args) { E> a1; E> a2 = new E>(); a1 = a2; // this won't compile, but why? // these things are permissible on a1: a1.setThing(new D()); a2.setThing(new D()); // now let's try doing the same thing to a2: a2.setThing(new D()); a2.setThing(new D()); // oops } 

新main方法的最后一行是为什么a1不能设置为a2。 如果编译器允许你这样做,那么你就可以将D 放入一个声明只能容纳D 的容器中。

从原始示例中不明显的原因是因为您没有使用限制性更强的E >类型创建引用该对象的单独变量。 但希望你现在可以看到,如果存在这样的引用,它的类型安全性会因你尝试的任务而受到影响。

不。
<? 扩展C>与<?不一样? extends Object>
如果是这种情况,它也会导致(未说明的)假设 – C扩展Object,并导致说…

C类{public void doSomethingMEaningful(); };

清单<? extends C> allAtSea = new ArrayList <...>(); 清单<? extends Object> allObjects = new ArrayList <...>(); allObjects.add(new Integer(88)); …

allAtSea.addAll(allObjects); …

allAtSea.get(…)doSomethingMeaningful(…)。 //呃哦..这找到了整数88

C ++ FAQ在21.3提供了一个清晰的例子