tuple new java generics collections

new - java value pair list



¿Por qué java.util.Properties implementa Map<Object, Object> y no Map<String, String> (5)

Compatibilidad al revés.

La clase java.util.Properties pretende representar un mapa donde las claves y los valores son ambas cadenas. Esto se debe a que los objetos de Properties se utilizan para leer archivos .properties , que son archivos de texto.

Entonces, ¿por qué en Java 5 modificaron esta clase para implementar Map<Object,Object> y no Map<String,String> ?

Los estados de javadoc :

Debido a que Properties hereda de Hashtable, los métodos put y putAll se pueden aplicar a un objeto Properties. Se desaconseja enérgicamente su uso ya que permiten a la persona que llama insertar entradas cuyas claves o valores no son cadenas. El método setProperty se debe usar en su lugar. Si se llama al método store o save en un objeto Properties "comprometido" que contiene una clave o un valor que no sea String, la llamada fallará.

Dado que se supone que las claves y los valores son cadenas, ¿por qué no aplicarlo estáticamente utilizando el tipo genérico adecuado?

Supongo que hacer que Properties implemente Map<String,String> no sería totalmente retrocompatible con el código escrito para pre-Java 5. Si tiene un código anterior que adhiere cadenas a un objeto Properties, entonces ese código ya no compilaría con Java 5 Pero ... ¿no es eso algo bueno? ¿No es el objetivo de los genéricos detectar estos tipos de errores en tiempo de compilación?


El motivo: el principio de sustitución de Liskov y la compatibilidad con versiones anteriores. Properties amplían Hashtable y, por lo tanto, deben aceptar todos los mensajes que Hashtable aceptaría, y eso significa aceptar put(Object, Object) . Y tiene que extender Hashtable simple en lugar de Hashtable<String, String> porque los genéricos se implementaron en la forma de compatibilización hacia abajo mediante el borrado de tipo , por lo que una vez que el compilador ha hecho lo suyo, no hay genéricos.


Originalmente se pretendía que Properties extendiera Hashtable<String,String> . Lamentablemente, la implementación de métodos de puente causó un problema. Properties definidas de tal manera causan que javac genere métodos sintéticos. Properties deben definir, por ejemplo, un método get que devuelva una String pero debe sobrescribir un método que devuelva Object . Entonces se agrega un método de puente sintético.

Supongamos que tiene una clase escrita en los malos viejos 1.4 días. Ha anulado algunos métodos en Properties . Pero lo que no ha hecho se anula los nuevos métodos. Esto conduce a un comportamiento involuntario. Para evitar estos métodos de puente, Properties extends Hashtable<Object,Object> . De forma similar, Iterable no devuelve un SimpleIterable (de solo lectura), porque eso habría agregado métodos a las implementaciones de Collection .


Porque lo hicieron con prisa en los primeros días de Java, y no se dieron cuenta de cuáles serían las implicaciones en cuatro versiones más adelante.

Se suponía que los genéricos formaban parte del diseño de Java desde el principio, pero la función se descartó por ser demasiado complicada y, en ese momento, innecesaria. Como resultado, muchos códigos en las bibliotecas estándar se escriben con la suposición de colecciones no genéricas. Tomó el lenguaje prototipo "Pizza" de Martin Odersky para mostrar cómo se podían hacer bastante bien manteniendo una compatibilidad casi perfecta con códigos Java y bytecode. El prototipo condujo a Java 5, en el cual las clases de colecciones fueron modernizadas con genéricos de una manera que permitía que el código viejo siguiera funcionando.

Desafortunadamente, si tuvieran que retroactivamente hacer que Properties heredara de Map<String, String> , entonces el siguiente código previamente válido dejaría de funcionar:

Map<Object, Object> x = new Properties() x.put("flag", true)

Por qué alguien haría eso está más allá de mí, pero el compromiso de Sun con la compatibilidad con versiones anteriores en Java ha pasado de ser heroico a ser inútil.

Lo que ahora aprecian la mayoría de los observadores educados es que las Properties nunca deberían haber heredado de Map en absoluto. En su lugar, debe envolver Map , exponiendo solo aquellas características de Map que tengan sentido.

Desde la reinvención de Java, Martin Odersky ha creado el nuevo lenguaje Scala, que es más limpio, hereda menos errores y abre nuevos caminos en varias áreas. Si encuentra las molestias de Java molestas, échele un vistazo.


Un trazador de líneas (dos líneas para no advertencias) para crear un mapa a partir de las propiedades:

@SuppressWarnings({ "unchecked", "rawtypes" }) Map<String, String> sysProps = new HashMap(System.getProperties());