2009-01-16 14 views
8

que tengo una clase de legado que la clase en sí no es un genérico, pero uno de sus métodos devuelven tipo utiliza genéricos:referencia no genérica a resultados de la clase genérica de tipos de retorno no genéricos

public class Thing { 
    public Collection<String> getStuff() { ... } 
} 

getStuff() usos genéricos para devolver una colección de cadenas. Por lo tanto puedo iterar sobre getStuff() y no hay necesidad de emitir los elementos a un String:

Thing t = new Thing(); 
for (String s: t.getStuff()) // valid 
{ ... } 

Sin embargo, si cambio Thing a sí misma como un genérico, pero mantener todo lo demás igual:

public class Thing<T> { 
    public Collection<String> getStuff() { ... } 
} 

y luego siga utilizando la referencia no genérica a Thing, getStuff() ya no devuelve Collection<String> y en su lugar devuelve un Collection sin tipo. Por lo tanto, el código del cliente no compila:

Thing t = new Thing(); 
for (String s: t.getStuff()) // compiler complains that Object can't be cast to String 
{ ... } 

¿Por qué es esto? ¿Cuáles son las soluciones?

Supongo que al utilizar una referencia no genérica a una clase genérica, Java desactiva todos los genéricos para toda la clase. Esto es doloroso, porque ahora he roto mi código de cliente al hacer que Thing sea genérico.

Edición: Estoy haciendo Thing genérico para otro método que no se encuentra en el código de ejemplo anterior. Mi pregunta es educativa sobre por qué lo anterior no se puede hacer.

Respuesta

10

Ok, toma dos, he entendido mal tu pregunta.

Cuando delcare Thing (esto se llama un prima de tipo) en lugar de Thing<?> (tipo parametrizado) el compilador de Java se estropea todos los argumentos genéricos, incluso misma (como en su caso) el tipo genérico del método no tiene nada que ver con el tipo genérico de la clase.

Desde el (excelente) Java Generics FAQ:

Can I use a raw type like any other type?

métodos o constructores de un tipo cruda tener la firma que tendrían después del tipo de borrado.

Esta frase aparentemente inocuo y discreto describe el comportamiento en cuestión. Está utilizando Thing como tipo sin procesar, por lo que el tipo de devolución es Collection (no Collection<String>) ya que este es el tipo después del borrado de tipo.

Confused? No es sorprendente. Solo mira el tamaño de esas preguntas frecuentes. Probablemente hay alrededor de tres personas en la tierra que comprenden las implicaciones completas de los genéricos de Java. Solo considere mi declaración favorita del JDK:

Enum<T extends Enum<T>> 

(Hay una explicación de eso en las preguntas frecuentes también).

+0

estoy haciendo cosa genérica, porque de otro método (que no figura en mi ejemplo). –

+0

Si cosa es cosa (y no la cosa ), no compilará. Sigue adelante e inténtalo. –

+0

malentendió la pregunta, cambió. – cletus

0

Falló debido a borrado.Puede leer más al respecto en estos Java Tutorials

0

Creo que esto es totalmente normal. En mi opinión, usando Thing t = new Thing(); para la clase genérica habilitada es totalmente un error. Cuando el compilador ve una clase genérica utilizada como clase sin parámetro de tipo, cree que debe borrar todos los tipos genéricos de esa clase. Así es como puedes compilar códigos antiguos sin el uso de genéricos en nuevos compiladores de Java y el compilador permite que los códigos antiguos usen genéricamente las clases habilitadas (por ejemplo, java.util.ArrayList) sin ningún problema. (y así es como java no necesita separar System.Collection.Generic.List y System.Collection.List como C#). Puede ejecutar Thing t = new Thing(); agregando un parámetro de tipo simple en él, Thing<Object> t = new Thing<Object>();, lo único que el compilador necesita es asegurarse de que está usando conscientemente Java. Nunca culpo a Java por su gran compatibilidad con versiones anteriores.

Yo sé que soy un poco tarde: D

Cuestiones relacionadas