3

在这个问题中,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());

我能发现的唯一区别是,在 JavaSpecialists 博客中,Enumeration来自 aVector的签名是:

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());
    }
}

但!!那个时事通讯的重点不是解决这个问题,而是避免需要指定一个泛型类型,只是因为语法看起来很丑!!

所以..我的问题是:

怎么了?

IterableEnumeration当参数是Enumeration其类型时,为什么不创建工作实例<? 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);
    }
}

我想明白!!

4

2 回答 2

3

我不确定 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);
    }
于 2009-03-07T02:47:14.163 回答
0

这里的根本问题是,当ZipFile更改为支持泛型时,维护者选择了entries()方法的返回类型Enumeration<? extends ZipEntry>(大概是为了让子类中的方法 JarFile可以返回Enumeration<JarEntry>)。这会导致您看到的问题。

因为Enumeration<T>是协变使用的(因为它总是 - 它只返回值),你应该总是让方法参数取Enumeration<? extends T>.

于 2009-08-04T18:50:12.080 回答