如何修复此Java泛型通配符错误?
-
05-07-2019 - |
题
在这个问题中,TofuBeer在创建泛化IterableEnumeration
时遇到了问题。
答案来自jcrossley3指向此链接 http://www.javaspecialists.eu/ archive / Issue107.html 几乎解决了这个问题。
还有一件事我没有得到。正如埃里克森有效指出的那样,真正的问题是:
构造参数化类型
时,无法指定通配符
但是删除声明中的通配符也不起作用:
final IterableEnumeration<ZipEntry> iteratable
= new IterableEnumeration<ZipEntry>(zipFile.entries());
导致以下错误:
Main.java:19: cannot find symbol
symbol : constructor IterableEnumeration(java.util.Enumeration<capture#469 of ? extends java.util.zip.ZipEntry>)
location: class IterableEnumeration<java.util.zip.ZipEntry>
final IterableEnumeration<ZipEntry> iteratable = new IterableEnumeration<ZipEntry>( zipFile.entries());
^
1 error
但是JavaSpecialist中的示例确实有效:
IterableEnumeration<String> ie =
new IterableEnumeration<String>(sv.elements());
我能发现的唯一区别是,在JavaS专家博客中,Enumeration
来自一个Vector
,其签名是:
public Enumeration<E> elements()
而失败的那个来自ZipFile
,签名是:
public Enumeration<? extends ZipEntry> entries()
最后,所有这些都被for-each构造和链接
中建议的静态make方法所吸收for(final ZipEntry entry : IterableEnumeration.make( zipFile.entries() )) {
if(!(entry.isDirectory())) {
names.add(entry.getName());
}
}
但是!!该通讯中的要点不是解决这个问题,而是为了避免指定泛型类型,只是因为语法看起来很难看!
所以..我的问题是:
发生了什么事?
为什么在参数为<? extends SomeClass>
且<=>类型为<=>时,不创建<=>实例?为什么make for-each构造吞下了这个问题?!!!
为什么这样做:
for(final ZipEntry entry : IterableEnumeration.make( zipFile.entries() )) {
但这不起作用?
final IterableEnumeration<ZipEntry> iteratable
= IterableEnumeration.make( zipFile.entries() );
以下是TofuBeer原始代码的(稍微)修改版本:
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.Vector;
public class Main {
private ZipFile zipFile;
public Set<String> entries() {
final Vector<ZipEntry> vector = new Vector<ZipEntry>();
// why this works.
//final IterableEnumeration<ZipEntry> iteratable = new IterableEnumeration<ZipEntry>( vector.elements() );
// but this do not.
//final IterableEnumeration<ZipEntry> iteratable = new IterableEnumeration<ZipEntry>( zipFile.entries() );
// nor this
final IterableEnumeration<ZipEntry> iteratable = IterableEnumeration.make( zipFile.entries() );
// And what's with the for-each that doesn't care about the type?
final Set<String> names = new HashSet<String>();
for(final ZipEntry entry : IterableEnumeration.make( zipFile.entries() )) {
if(!(entry.isDirectory())) {
names.add(entry.getName());
}
}
return (names);
}
}
class IterableEnumeration<T> implements Iterable<T> {
private final Enumeration<T> enumeration;
public IterableEnumeration(final Enumeration<T> e) {
enumeration = e;
}
public Iterator<T> iterator() {
return new Iterator<T>() {
public boolean hasNext() {
return (enumeration.hasMoreElements());
}
public T next() {
return (enumeration.nextElement());
}
public void remove() {
throw new UnsupportedOperationException("Cannot remove via an Enumeration");
}
};
}
// As suggested by http://www.javaspecialists.eu/archive/Issue107.html
// but doesn't help with: final IterableEnumeration<ZipEntry> iteratable = IterableEnumeration.make( zipFile.entries() );
public static <T> Iterable<T> make(Enumeration<T> en) {
return new IterableEnumeration<T>(en);
}
}
我想明白!!
解决方案
我不确定foreach循环发生了什么,但是你需要在你的IterableEnumeration声明中添加通配符以接受从ZipFile.entries()返回的未指定类型。
替换
private final Enumeration<T> enumeration;
public IterableEnumeration(final Enumeration<T> e) {
enumeration = e;
}
public static <T> Iterable<T> make(Enumeration<T> en) {
return new IterableEnumeration<T>(en);
}
使用
private final Enumeration<? extends T> enumeration;
public IterableEnumeration(final Enumeration<? extends T> e) {
enumeration = e;
}
public static <T> Iterable<T> make(Enumeration<? extends T> en) {
return new IterableEnumeration<T>(en);
}
其他提示
这里的根本问题是 ZipFile 被更改为支持泛型,维护者选择创建entries()
方法的返回类型Enumeration<? extends ZipEntry>
(可能是因为子类JarFile
中的方法可以返回Enumeration<JarEntry>
)。这会导致您遇到的问题。
因为Enumeration<T>
被共同使用(因为它总是 - 它只返回值),所以你应该始终使方法参数取Enumeration<? extends T>
。