2009-04-21 16 views
5

Con nombre local classes se usan muy raramente, por lo general, las clases locales son anónimas. ¿Alguien sabe por qué el código siguiente genera una advertencia del compilador?Java: clase local y genéricos, ¿por qué la advertencia del compilador?

public class Stuff<E> { 
    Iterator<E> foo() { 
    class InIterator implements Iterator<E> { 
     @Override public boolean hasNext() { return false; } 
     @Override public E next() { return null; } 
     @Override public void remove() { } 
    } 
    return new InIterator(); 
    } 
} 

La advertencia está en new InIterator() y dice

[unchecked] unchecked conversion 
found : InIterator 
required: java.util.Iterator<E> 

Si la clase, sin cambios, se hace anónima, o si se hace un miembro, la advertencia desaparece. Sin embargo, como clase local con nombre, requiere una declaración class InIterator<E> implements ... para que la advertencia desaparezca.

¿Qué está pasando?

+0

Solo por curiosidad, mi compilador no se queja de esta advertencia ... ¿Qué JVM estás usando? –

+0

Actualización de Sun Java 6 12 – Yardena

Respuesta

1

Ahora estoy convencido de que es un error de Java. Las soluciones anteriores que agregan un parámetro genérico a InIterator que oculta o reemplaza E no son útiles, ya que impiden que el iterador haga algo útil, como devolver un elemento de tipo E - Material E.

Sin embargo, esto se compila con sin advertencias (gracias Jorn por la pista):

public class Stuff<E> { 
    E bar; 
    Iterator<E> foo() { 
    class InIterator<Z> implements Iterator<E> { 
     @Override public boolean hasNext() { return false; } 
     @Override public E next() { return bar; } 
     @Override public void remove() { } 
    } 
    return new InIterator<Void>(); 
    } 
} 

Definitivamente un error.

+0

¿Se puede presentar un error y publicar el enlace? Me has hecho a todos curioso. –

+0

bueno, de acuerdo con tweakt a continuación no hay advertencia en la actualización 13. Comprobaré, pero suponiendo que tenga razón, significa que ERA un error :-) – Yardena

+0

Ah, está bien. ¿Has verificado para ver si está en la lista de errores en alguna parte? –

3

Creo que lo que está sucediendo es que está ignorando el argumento de tipo genérico al nombrar InIterator sin una referencia al genérico en la firma (aunque esté presente en la interfaz).

Esto entra en la categoría de advertencias tontas del compilador: ha escrito la clase para que las instancias 100% InIterator implementen Iterator<E>, pero el compilador no lo reconoce. (Supongo que esto depende del compilador. No veo la advertencia en mi compilador de Eclipse, pero sé que el compilador de Eclipse maneja genéricos de forma ligeramente diferente que el compilador JDK.)

Argumento que esto es menos claro, y menos cerca de lo que quiere decir, pero tal vez más amigable para el compilador, y en última instancia equivalente:

public class Stuff<E> { 
    Iterator<E> foo() { 
    class InIterator<F> implements Iterator<F> { 
     @Override public boolean hasNext() { return false; } 
     @Override public E next() { return null; } 
     @Override public void remove() { } 
    } 
    return new InIterator<E>(); 
    } 
} 
+0

Gracias David. IntelliJ IDEA tampoco mostró ninguna advertencia, solo Sun javac. Sé cómo solucionar esto, simplemente me pregunto si hay alguna razón extraña pero legítima para este comportamiento del compilador, o si es un error. – Yardena

+0

Ahh, las diferencias entre compilador IDE y javac ... lo molesto :( – Jorn

+0

No está del todo claro si se trata de un error que InIterator no es un iterador o que InIterator implementa iterador . –

1

Hmm, no hay advertencias aquí.

import java.util.Iterator; 

public class Stuff<E> { 
    Iterator<E> foo() { 
     class InIterator implements Iterator<E> { 
      public boolean hasNext() { 
       return false; 
      } 

      public E next() { 
       return null; 
      } 

      public void remove() { 
      } 
     } 
     return new InIterator(); 
    } 

    public static void main(String[] args) { 
     Iterator<String> i = new Stuff<String>().foo(); 
    } 
} 
+0

Hm, ¿qué compilador estás usando? – Yardena

+0

probado dentro de Eclipse (3.4), así como con Sun JDK 1.5.0.18 y 1.6.0.13 –

+0

hay una advertencia para Sun 1.6.0_11 y 1.6.0_12, voy a marcar 13, ¡gracias! – Yardena

1

Sí, también estoy de acuerdo en que esto debería ser un error. Si "saca" la clase local del método a una clase de miembro, también funciona bien. Y no hay mucha diferencia entre los dos, excepto diferente alcance y acceso a las variables locales.

public class Stuff<E> { 
    class InIterator implements Iterator<E> { 
    @Override public boolean hasNext() { return false; } 
    @Override public E next() { return null; } 
    @Override public void remove() { } 
    } 
    Iterator<E> foo() { 
    return new InIterator(); 
    } 
} 
Cuestiones relacionadas