3 Stimmen

Wie behebe ich diesen Java Generics Wildcard-Fehler?

In diesem question hatte TofuBeer Probleme mit der Erstellung eines generischen IterableEnumeration .

Die Antwort kam von jcrossley3, der auf diesen Link verwies http://www.javaspecialists.eu/archive/Issue107.html Damit war das Problem so gut wie gelöst.

Eine Sache verstehe ich immer noch nicht. Das eigentliche Problem war, wie von erickson treffend dargelegt, dass:

Bei der Konstruktion eines parametrisierten Typs können Sie keinen Platzhalter angeben

Aber auch das Entfernen des Platzhalters in der Deklaration hat nicht funktioniert:

final IterableEnumeration<ZipEntry> iteratable 
                  = new IterableEnumeration<ZipEntry>(zipFile.entries());

Dies führt zu dem folgenden Fehler:

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

Aber die Beispiele im JavaSpecialist funktionieren:

  IterableEnumeration<String> ie =
              new IterableEnumeration<String>(sv.elements());

Der einzige Unterschied, den ich feststellen kann, ist, dass im JavaSpecialists-Blog die Enumeration kommt von einer Vector dessen Unterschrift lautet:

public Enumeration<E> elements()

während derjenige, der scheitert, von ZipFile dessen Unterschrift lautet:

public Enumeration<? extends ZipEntry> entries()

Schließlich wird all dies durch das for-each-Konstrukt und die statische make-Methode absorbiert, die in dem Link

for(final ZipEntry entry : IterableEnumeration.make( zipFile.entries() ))  {
    if(!(entry.isDirectory())) {
        names.add(entry.getName());
    }
}

Aber in diesem Rundschreiben ging es nicht darum, dieses Problem zu lösen, sondern zu vermeiden, dass ein allgemeiner Typ angegeben werden muss, nur weil die Syntax hässlich aussieht!!!

Meine Frage ist also:

Was geschieht hier?

Warum funktioniert die Erstellung einer Instanz von IterableEnumeration funktionieren, wenn der Parameter ein Enumeration deren Typ ist <? extends SomeClass> ? Und warum schluckt das Fabrikat für jedes Konstrukt das Problem?!!!

Warum funktioniert das?

for(final ZipEntry entry : IterableEnumeration.make( zipFile.entries() ))  {

aber das funktioniert nicht?

final IterableEnumeration<ZipEntry> iteratable
                     = IterableEnumeration.make( zipFile.entries() );

Nachfolgend finden Sie eine (leicht) modifizierte Version des ursprünglichen Codes von 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);
    }
}

Ich will es verstehen!!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X