2012-06-08 21 views
18

He leído todo el libro SCJP6 del libro Sierra and Bates, obtuve el 88% del examen.¿Qué es este uso de genéricos en Java? X. <Y> método()

Pero aún así, nunca oído hablar de cómo este tipo de código funciona, ya que no está explicado en el capítulo de los genéricos:

Collections.<TimeUnit>reverseOrder() 

¿Qué es este tipo de uso de genéricos? Lo descubrí en algún código pero nunca leí nada al respecto. Me parece que permite dar algo de ayuda para escribir inferencia. He intentado buscar sobre eso pero no es tan fácil de encontrar (y ni siquiera está en el libro/examen SCJP)

¿Puede alguien darme una explicación adecuada de cómo funciona, que son todas las usecases, etc.

Gracias


Editar Gracias por las respuestas, pero me esperaba más detalles :) así que si alguien quiere añadir un poco más información:

¿Qué pasa con los casos más complejos como

  • Usando un tipo declarado en clase, ¿puedo hacer algo como Collections.<T>reverseOrder() por ejemplo?
  • ¿Cómo usar extends, super?
  • Usando ?
  • Dando al compilador sólo ayuda parcial (es decir O.manyTypesMethod<?,MyHelpTypeNotInfered,?,?,?,?,?>())

Respuesta

18

Es especificación de tipo explícito de un método genérico. Siempre puedes hacerlo, pero en la mayoría de los casos no es necesario. Sin embargo, se requiere en algunos casos si el compilador no puede inferir el tipo genérico por sí mismo.

Vea un ejemplo hacia el final de the tutorial page.

Actualización: Solo el primero de sus ejemplos es válido. El argumento de tipo explícito debe ser, bueno, explícito, por lo que no se permiten comodines, extends o super. Además, o bien especificas cada argumento de tipo explícitamente o ninguno de ellos; es decir, el número de argumentos de tipo explícito debe coincidir con el número de parámetros de tipo del método llamado. Se permite un parámetro de tipo como T si está bien definido en el alcance actual, p. como un parámetro de tipo de la clase adjunta.

3

Usted es 100% correcto, es para ayudar con la inferencia de tipo. La mayoría de las veces no es necesario hacer esto en Java, ya que puede inferir el tipo (incluso desde el lado izquierdo de una tarea, lo cual es bastante bueno). Esta sintaxis se trata en el generics tutorial en el sitio web de Java.

0

En este caso, es una forma de decirle al método reverseOrder qué tipo de ordenamiento se debe imponer al objeto, según el tipo que especifique. El comparador necesita obtener información específica sobre cómo ordenar cosas.

+0

Lo sentimos, pero el tipo en este caso no tiene nada que ver con el tipo de orden: puedo dar el tipo que quiero, bajo el capó siempre será el mismo objeto en tiempo de ejecución haciendo exactamente lo mismo. El tipo especificado solo ayuda al compilador –

1

Solo una pequeña adición a las otras respuestas.

Al conseguir el error del compilador de acuerdo:

Si bien el enfoque "tradicional" casting

(Comparator<TimeUnit>) Collections.reverseOrder() 

tiene una apariencia similar a los genéricos se acercan

Collections.<TimeUnit>reverseOrder() 

el enfoque de fundición es, por supuesto, no escriba -seguro (posible excepción de tiempo de ejecución), mientras que el enfoque genérico crearía un error de compilación, si hay un problema. Por lo tanto, se prefiere el enfoque genérico, por supuesto.

1

Como las otras respuestas se han aclarado, es para ayudar al compilador a determinar qué tipo genérico desea. Por lo general, se necesita cuando se utilizan los métodos de utilidad Collections que devuelven algo de un tipo genérico y no reciben parámetros.

Por ejemplo, considere los métodos Collections.empty*, que devuelven una colección vacía. Si usted tiene un método que espera un Map<String, String>:

public static void foo(Map<String, String> map) { } 

Usted puede no pasar directamente Collections.emptyMap() a ella. The compiler will complain incluso si sabe que espera un Map<String, String>:

// This won't compile. 
foo(Collections.emptyMap()); 

Tienes que explícitamente declare the type you want in the call, que creo que se ve bastante feo:

foo(Collections.<String, String>emptyMap()); 

O se puede omitir que la declaración de tipo en el método llame si assign the emptyMap return value to a variable antes de pasarlo a la función, lo que creo que es bastante ridículo, porque parece innecesario y muestra que el compilador es realmente inconsistente: a veces hace tipo infere na vez en métodos genéricos con ningún parámetro, pero a veces no lo hace:

Map<String, String> map = Collections.emptyMap(); 
foo(map); 

Puede que no parezca como una cosa muy importante, pero cuando los tipos genéricos comienza a recibir más complejos (por ejemplo, Map<String, List<SomeOtherGenericType<Blah>>>) un tipo de comienza deseando que Java tenga una inferencia de tipo más inteligente (pero, como no, uno probablemente comenzará a escribir nuevas clases donde no sea necesario, solo para evitar todos esos feos <> = D).

+0

Gracias. ¿Quieres decir que la inferencia de tipo no funciona para los parámetros del método? ¿Es siempre el caso? –

+0

@SebastienLorber No estoy seguro. Además, creo que Java 7 agregó algunas características de inferencia de tipo, aunque el primer ejemplo [aún no compila] (http://ideone.com/4H1yx). Una cosa que se agregó fue la inferencia de tipos para llamadas de constructor genéricas, pero funciona de la misma manera que parece ser el método genérico, es decir, [la asignación a una variable] (http://ideone.com/sNoD6) utiliza la inferencia de tipo pero utilizando el La expresión [como parámetro] (http://ideone.com/nHpfX) directamente no: S – epidemian

Cuestiones relacionadas