sirve setsize setpreferredsize redimensionar que para paquete ejemplos ejemplo contenedores componentes clases java generics collections type-inference

java - setsize - ¿Por qué el uso de Collections.emptySet() con genéricos funciona en la asignación pero no como un parámetro de método?



setsize java para que sirve (4)

Entonces, tengo una clase con un constructor como este:

public FilterList(Set<Integer> labels) { ... }

y quiero construir un nuevo objeto FilterList con un conjunto vacío. Siguiendo el consejo de Joshua Bloch en su libro Effective Java, no quiero crear un nuevo objeto para el conjunto vacío; Usaré Collections.emptySet() lugar:

FilterList emptyList = new FilterList(Collections.emptySet());

Esto me da un error, quejándome de que java.util.Set<java.lang.Object> no es un java.util.Set<java.lang.Integer> . OK, ¿qué tal esto?

FilterList emptyList = new FilterList((Set<Integer>)Collections.emptySet());

¡Esto también me da un error! Ok, ¿qué tal esto?

Set<Integer> empty = Collections.emptySet(); FilterList emptyList = new FilterList(empty);

Oye, funciona! ¿Pero por qué? Después de todo, Java no tiene inferencia de tipo, por lo que se obtiene una advertencia de conversión sin Set<Integer> foo = new TreeSet() si se Set<Integer> foo = new TreeSet() lugar de Set<Integer> foo = new TreeSet<Integer>() . Pero Set<Integer> empty = Collections.emptySet(); funciona sin siquiera una advertencia. ¿Porqué es eso?



La respuesta corta es: esa es una limitación de la inferencia de tipo en el sistema genérico de Java. Puede inferir tipos genéricos contra variables concretas, pero no contra parámetros de método.

Sospecho que esto se debe a que los métodos se envían dinámicamente según la clase de tiempo de ejecución del objeto propietario, por lo que en tiempo de compilación (cuando se resuelve toda la información genérica) no se puede saber con certeza cuál será la clase del parámetro del método y, por lo tanto, no puedo inferir. Las declaraciones de variables son agradables y constantes, por lo que puedes.

Alguien más podría dar más detalles y / o un buen enlace. :-)

En cualquier caso, siempre puede especificar los parámetros de tipo de forma explícita para llamadas genéricas como esta:

Collections.<Integer>emptySet();

o incluso varios parámetros a la vez, por ejemplo

Collections.<String, Boolean>emptyMap(); // Returns a Map<String, Boolean>

Esto a menudo se ve un poco más limpio que tener que lanzar, en casos donde la inferencia no entra.


Quieres hacer esto:

FilterList emptyList = new FilterList(java.util.Collections.<Integer>emptySet());

Eso le dice al método emptySet que su parámetro genérico debe explícitamente por Integer lugar del Object defecto. Y sí, la sintaxis es completamente funky y no intuitiva para esto. :)


tratar

FilterList emptyList = new FilterList(Collections.<Integer>emptySet());

Puede forzar el parámetro de tipo para los métodos que los tienen, en los casos donde la inferencia no es lo suficientemente buena, o para permitirle usar subtipos; por ejemplo:

// forces use of ArrayList as parameter instead of the infered List List<String> l = someObject.<ArrayList<String> methodThatTakesTypeParamForReturnType();