programación programacion libro lenguaje ejemplo desde cero java generics

lenguaje - libro de programacion en java netbeans pdf



El método tiene el mismo borrado que otro método en tipo (6)

Defina un solo método sin tipo como void add(Set ii){}

Puede mencionar el tipo al llamar al método según su elección. Funcionará para cualquier tipo de conjunto.

¿Por qué no es legal tener estos dos métodos en la misma clase?

class Test{ void add(Set<Integer> ii){} void add(Set<String> ss){} }

Me sale el compilation error

El método add (Set) tiene el mismo comando add (Set) que otro método en el tipo Test.

mientras puedo solucionarlo, me preguntaba por qué a javac no le gusta esto.

Puedo ver que en muchos casos, la lógica de estos dos métodos sería muy similar y podría ser reemplazada por una sola

public void add(Set<?> set){}

Método, pero este no es siempre el caso.

Esto es muy molesto si quiere tener dos constructors que tomen esos argumentos porque entonces no puede simplemente cambiar el nombre de uno de los constructors .


El problema es que Set<Integer> y Set<String> realidad se tratan como un Set desde la JVM. La selección de un tipo para el Conjunto (Cadena o Entero en su caso) es solo el azúcar sintáctico utilizado por el compilador. La JVM no puede distinguir entre Set<String> y Set<Integer> .


Esta regla está destinada a evitar conflictos en el código heredado que todavía utiliza tipos sin procesar.

Aquí hay una ilustración de por qué esto no estaba permitido, extraído del JLS. Supongamos que, antes de que los genéricos se introdujeran en Java, escribí un código como este:

class CollectionConverter { List toList(Collection c) {...} }

Extiendes mi clase, así:

class Overrider extends CollectionConverter{ List toList(Collection c) {...} }

Después de la introducción de los genéricos, decidí actualizar mi biblioteca.

class CollectionConverter { <T> List<T> toList(Collection<T> c) {...} }

No está listo para realizar actualizaciones, por lo que deja su clase Overrider solo. Para anular correctamente el método toList() , los diseñadores del lenguaje decidieron que un tipo sin formato era "equivalente de reemplazo" a cualquier tipo generado. Esto significa que aunque su firma de método ya no es formalmente igual a la firma de mi superclase, su método aún se invalida.

Ahora, el tiempo pasa y decides que estás listo para actualizar tu clase. Pero lo arruinas un poco, y en lugar de editar el método existente, raw toList() , agregas un nuevo método como este:

class Overrider extends CollectionConverter { @Override List toList(Collection c) {...} @Override <T> List<T> toList(Collection<T> c) {...} }

Debido a la equivalencia de anulación de tipos sin formato, ambos métodos están en una forma válida para anular el toList(Collection<T>) . Pero, por supuesto, el compilador necesita resolver un solo método. Para eliminar esta ambigüedad, a las clases no se les permite tener múltiples métodos que sean equivalentes a los de anulación, es decir, múltiples métodos con los mismos tipos de parámetros después del borrado.

La clave es que esta es una regla de lenguaje diseñada para mantener la compatibilidad con el código antiguo utilizando tipos sin formato. No es una limitación requerida por el borrado de parámetros de tipo; como la resolución del método se produce en tiempo de compilación, habría sido suficiente agregar tipos genéricos al identificador del método.


Esto se debe a que los genéricos de Java se implementan con la eliminación de tipos .

Sus métodos se traducirían, en tiempo de compilación, a algo como:

La resolución del método ocurre en tiempo de compilación y no considera los parámetros de tipo. ( ver respuesta de erickson )

void add(Set ii); void add(Set ss);

Ambos métodos tienen la misma firma sin los parámetros de tipo, de ahí el error.


Java genéricos utiliza borrado de tipo. El bit en los corchetes angulares ( <Integer> y <String> ) se elimina, por lo que terminará con dos métodos que tienen una firma idéntica (el add(Set) que ve en el error). Eso no está permitido porque el tiempo de ejecución no sabría cuál usar para cada caso.

Si Java alguna vez obtiene genéricos reificados, entonces podría hacer esto, pero probablemente sea poco probable ahora.


Podría ser posible que el compilador traduzca Set (Integer) a Set (Object) en el código de bytes de Java. Si este es el caso, Set (Integer) se usaría solo en la fase de compilación para la comprobación de la sintaxis.