이 Java Generics 와일드 카드 오류를 어떻게 수정합니까?
-
05-07-2019 - |
문제
이것에서 의문, tofubeer는 일반화 된 것을 만드는 데 문제가있었습니다 IterableEnumeration
.
답은 Jcrossley3 이이 링크를 가리키는 것에서 나왔습니다 http://www.javaspecialists.eu/archive/issue107.html 문제를 거의 해결했습니다.
내가 얻지 못하는 것이 여전히 있습니다. Erickson이 효과적으로 지적했듯이 실제 문제는 다음과 같습니다.
매개 변수화 된 유형을 구성 할 때 와일드 카드를 지정할 수 없습니다.
그러나 선언에서 와일드 카드를 제거하는 것은 작동하지 않았습니다.
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
a에서 온다 Vector
서명은 다음과 같습니다.
public Enumeration<E> elements()
실패한 것은 나옵니다 ZipFile
서명은 다음과 같습니다.
public Enumeration<? extends ZipEntry> entries()
마지막으로,이 모든 것은 링크에서 제안 된 For-each Construct와 정적 메소드에 의해 흡수됩니다.
for(final ZipEntry entry : IterableEnumeration.make( zipFile.entries() )) {
if(!(entry.isDirectory())) {
names.add(entry.getName());
}
}
하지만!! 그 뉴스 레터의 요점은이 문제를 해결하는 것이 아니라 구문이 추악 해 보이기 때문에 일반 유형을 지정할 필요가 없습니다!
그래서 .. 내 질문은 다음과 같습니다.
무슨 일이 일어나고 있습니까?
인스턴스를 만드는 이유는 무엇입니까? IterableEnumeration
매개 변수가 an 일 때 작동합니다 Enumeration
누구의 유형입니다 <? extends SomeClass>
? 그리고 왜 마찬가지로 건설이 문제를 삼키는가? !!!
왜이 효과가 있습니까?
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 루프에서 무슨 일이 일어나고 있는지 잘 모르겠지만 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);
}
다른 팁
여기서 근본적인 문제는 언제입니다 압축 파일 제네릭을 지원하기 위해 변경되었으며 관리자는 반환 유형을 entries()
행동 양식 Enumeration<? extends ZipEntry>
(아마도 서브 클래스의 방법이 될 것입니다 JarFile
돌아올 수 있습니다 Enumeration<JarEntry>
). 이것은 당신이보고있는 문제를 일으킨다.
왜냐하면 Enumeration<T>
공분산으로 사용됩니다 (항상 - 값만 리턴하는 것만으로도), 항상 방법 인수를 가져 가야합니다. Enumeration<? extends T>
.