为什么java报告这是类型不匹配?

bfnvny8b  于 2021-06-29  发布在  Java
关注(0)|答案(2)|浏览(441)

我已经知道 Iterator 包含扩展 ZipEntry 但我不能在没有错误的情况下进行向下转换:

ZipFile zf = new ZipFile("a.zip");

// Type mismatch: cannot convert from Iterator<capture#4-of ? extends ZipEntry> to Iterator<ZipEntry>
Iterator<ZipEntry> it = zf.entries().asIterator();

下载在java中不是错误:

String a = "";

// Works fine
Object b = a;

确切的返回类型是 Iterator<? extends ZipEntry> 但是我不需要原始类型,因为我只使用 ZipEntry .
如果我投的话,我还是会得到一个警告:

// Type safety: Unchecked cast from Iterator<capture#4-of ? extends ZipEntry> to Iterator<ZipEntry>
Iterator<ZipEntry> it = (Iterator<ZipEntry>)zf.entries().asIterator();

如果我已经知道的话,不加检查的石膏有什么问题 ? extends ZipEntry ? 为什么这样不安全?

y3bcpkx1

y3bcpkx11#

java泛型允许程序员在编译时绑定(或限制)类处理的元素类型。不要忘记java泛型在运行时并不存在,它们被删除了(如果您不知道的话,可以在google上搜索“java类型删除”以获取更多细节)。
在您的示例中,调用返回的迭代器 zf.entries().asIterator() 绑定到zipentry的任何子类,但不绑定到zipentry类本身。因此编译器检测到您正在将迭代器绑定到zipentry类,而zipentry类被显式地排除在返回的迭代器可以处理的所有可能类的集合之外。
通过编写代码

Iterator<? extends ZipEntry> it = zf.entries().asIterator();

您同意zipfile类公开的接口,并且Assert迭代器将只返回zipentry的某个子类的示例,而不会返回zipentry类的直接示例。
如果你写信

Iterator<ZipEntry> it = ...

您允许迭代器同时返回zipentry的示例及其所有子类的示例。
这就是我们之间的区别 Iterator<ZipEntry> 以及 Iterator<? extends ZipEntry>

xxe27gdn

xxe27gdn2#

Iterator<? extends ZipEntry> 表示未知类型的迭代器。我们唯一知道的是它是 ZipEntry 或者是 ZipEntry . 换句话说,可能是 Iterator<ZipEntry> , Iterator<JarEntry> ,或 Iterator<SomeOtherSubclass> 实际上。
因为这个,你不能确定 Iterator<? extends ZipEntry> 可以分配给类型的变量 Iterator<ZipEntry> . 当然,如果是的话 Iterator<ZipEntry> ,则可以分配它,但也可以 Iterator<JarEntry> ,或 Iterator<SomeOtherSubclass> ,在这种情况下你不能。 Foo<T> 以及 Foo<U> 是不相关的类型,即使 T 是的一个子类 U . 读一读这篇文章,了解为什么这对你来说是正确的 List<T> 以及 List<U> .
但在这种情况下,这个论点(来自链接的帖子):

// Illegal code - because otherwise life would be Bad
List<Dog> dogs = new ArrayList<Dog>(); // ArrayList implements List
List<Animal> animals = dogs; // Awooga awooga
animals.add(new Cat());
Dog dog = dogs.get(0); // This should be safe, right?

不适用于 Iterator s、 因为您只能从迭代器中获取内容,而不能添加内容。事实上,您可以在迭代器上执行的所有操作都是安全的,即使您是被允许的 Iterator<Animal> animals = dogs; . 但是,编译器不会自动检查所有操作是否安全。
java的工作方式是,当您使用泛型类型时,您可以说“请让我分配” Iterator<JarEntry>Iterator<ZipEntry> ,并且不允许我使用任何不安全的操作”。这样做的语法是:

Iterator<? extends ZipEntry> it = zf.entries().asIterator();

(这称为使用站点差异。)
这种“不允许我使用任何不安全的操作”类型与 asIterator .
Iterator 如果没有任何这样的不安全操作,您将获得与常规操作完全相同的接口 Iterator<ZipEntry> .
把这个和你在电脑上用的时候比较一下 List . 你不可能 add 有什么事吗 List<? extends ZipEntry> ,例如。

相关问题