84 votos

¿Qué me importa que Java no tiene genéricos cosificadas?

Esto surgió como una pregunta que le hice en una entrevista recientemente como algo que el candidato desea ver en el lenguaje Java. Es comúnmente identificado como un dolor que Java no se han materializado los genéricos pero, cuando empujó, el candidato no podía decirme el tipo de cosas que él podría haber logrado estaban allí.

Obviamente porque primas tipos son permitidos en Java (y no seguros de cheques), es posible subvertir los medicamentos genéricos y terminar con un List<Integer> de que (por ejemplo) en realidad contiene Strings. Esto claramente podría ser imposible eran el tipo de información concreta; pero no debe ser más que esto!

Podría la gente de publicar ejemplos de cosas que ellos realmente quieren hacer, fueron alabadas genéricos disponibles? Me refiero, obviamente, usted podría obtener el tipo de un List en tiempo de ejecución - pero ¿qué quiere usted hacer con ella?

public <T> void foo(List<T> l) {
   if (l.getGenericType() == Integer.class) {
       //yeah baby! err, what now?

EDIT: UNA rápida actualización a esto, ya que las respuestas parecen principalmente para estar preocupados acerca de la necesidad de pasar en un Class como un parámetro (por ejemplo, EnumSet.noneOf(TimeUnit.class)). Yo estaba buscando más por algo a lo largo de las líneas de donde esto simplemente no es posible. Por ejemplo:

List<?> l1 = api.gimmeAList();
List<?> l2 = api.gimmeAnotherList();

if (l1.getGenericType().isAssignableFrom(l2.getGenericType())) {
    l1.addAll(l2); //why on earth would I be doing this anyway?

77voto

RHSeeger Puntos 9217

Lo que más comúnmente me muerde es la incapacidad para aprovechar las múltiples despacho a través de múltiples tipos genéricos. Lo siguiente no es posible y hay muchos casos en los que sería la mejor solución:

 public void my_method(List<String> input) { ... }
public void my_method(List<Integer> input) { ... }
 

61voto

BalusC Puntos 498232

De las pocas veces que me encontré con esta "necesidad", que en última instancia se reduce a esta construcción:

public class Foo<T> {

    private T t;

    public Foo() {
        this.t = new T(); // Help?
    }

}

Esto no funciona en C# se supone que T tiene un defecto constructor. Usted puede incluso conseguir el tipo en tiempo de ejecución al typeof(T) y obtener los constructores por Type.GetConstructor().

El común de Java solución sería pasar la Class<T> como argumento.

public class Foo<T> {

    private T t;

    public Foo(Class<T> cls) throws Exception {
        this.t = cls.newInstance();
    }

}

(no necesariamente tiene que ser pasado como argumento de constructor, como argumento del método es también muy bien, lo anterior es sólo un ejemplo, también la try-catch se omite por razones de brevedad)

29voto

gustafc Puntos 13552

Tipo de seguridad viene a la mente. Downcasting para un parametrizar el tipo siempre va a ser inseguro, sin cosificada genéricos:

List<String> myFriends = new ArrayList();
myFriends.add("Alice");
getSession().put("friends", myFriends);
// later, elsewhere
List<Friend> myFriends = (List<Friend>) getSession().get("friends");
myFriends.add(new Friend("Bob")); // works like a charm!
// and so...
List<String> myFriends = (List<String>) getSession().get("friends");
for (String friend : myFriends) print(friend); // ClassCastException, wtf!?

También, abstracciones que le salía menos , al menos aquellos que pueden estar interesados en la información de tiempo de ejecución sobre sus parámetros de tipo. Hoy en día, si usted necesita cualquier tipo de información de tiempo de ejecución sobre el tipo de uno de los parámetros genéricos que han de pasar los Class a lo largo también. De esa manera, su interfaz externa depende de su implementación (ya sea que el uso de RTTI acerca de sus parámetros o no).

21voto

Turnor Puntos 1376

Usted sería capaz de crear matrices genéricas en el código.

 public <T> static void DoStuff() {
    T[] myArray = new T[42]; // No can do
}
 

10voto

sateesh Puntos 7967

Mi exposición a Java Geneircs es bastante limitada, y aparte de los puntos de otras respuestas ya hemos mencionado que hay un escenario explicado en el libro de Java Genéricos y Colecciones, de Maurice Naftalin y Felipe Walder, donde la reificación de los genéricos son útiles.

Dado que los tipos no son reifiable, no es posible tener Parametrizado excepciones.

Por ejemplo, la declaración de formulario a continuación no es válida.

class ParametericException<T> extends Exception // compile error

Esto es debido a que la captura de la cláusula comprueba si la excepción coincide con un tipo dado. Esta comprobación es la misma que la verificación realizada por la instancia de la prueba y desde el tipo no es reifiable el anterior formulario de declaración no es válida.

Si el código de arriba era válida, manejo de excepciones en la siguiente manera habría sido posible:

try {
     throw new ParametericException<Integer>(42);
} catch (ParametericException<Integer> e) { // compile error
  ...
}

El libro también menciona que si Java genéricos se definen de forma similar a las plantillas de C++ son define (expansión), que puede conducir a una aplicación más eficiente ya que esto ofrece más oportunidades de optimización. Pero no se ofrece ninguna explicación más que esto, por lo que cualquier explicación (punteros) a partir de los conocimientos de la gente sería de gran ayuda.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by: