2009-05-16 19 views
49

La clase java.util.Properties representa un mapa donde las claves y los valores son ambos Strings. Esto se debe a que los objetos Properties se utilizan para leer los archivos .properties, que son archivos de texto.Por qué java.util.Properties implementa Map <Object, Object> y no Map <String, String>

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

Los javadoc estados:

Dado que las propiedades hereda de Hashtable, la opción de venta y métodos 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á.

Desde las claves y valores se supone tanto para ser Cuerdas entonces por qué no hacer cumplir esa forma estática utilizando el tipo genérico adecuado?

Supongo que hacer Properties implementar Map<String,String> no sería totalmente compatible con el código escrito para pre-Java 5. Si tiene un código anterior que adhiere cadenas a un objeto de Propiedades, 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?

Respuesta

50

Porque lo hicieron con prisa en los primeros días de Java, y no se dieron cuenta de cuáles serían las implicaciones de 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 eliminó 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.

Por desgracia, si se tratara de hacer retroactivamente Properties Heredar del Map<String, String>, entonces el siguiente código válido anteriormente dejarían 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 hacia atrás en el Java ha ido más allá de lo heroico en lo inútil.

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

Desde la reinvención de Java, Martin Odersky ha seguido creando 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.

+1

En realidad Map x = new Properties() funciona de cualquier manera. Su gente pone cosas como properties.put ("flag", boolean.TRUE); He visto personas poner todo tipo de datos en un objeto de Propiedades, pero nunca una clave que no sea de Cadena. ;) –

+0

He actualizado mi respuesta para que quede más claro, gracias. –

+5

¡Espera un minuto! Mapa x = nuevas Propiedades() no es legal antes de Java 5, la sintaxis se introdujo en Java 5. Por lo tanto, la declaración "código previamente válido" es incorrecta. –

2

La razón: Liskov substitution principle y compatibilidad con versiones anteriores. Properties extiende Hashtable y por lo tanto debe aceptar todos los mensajes que Hashtable aceptaría, y eso significa aceptar put(Object, Object). Y tiene que extenderse simple Hashtable en lugar de Hashtable<String, String> porque los genéricos se implementaron en el modo de compatibilidad hacia abajo a través de type erasure, por lo que una vez que el compilador ha hecho lo suyo, no hay genéricos.

+3

no creo que el principio de sustitución Liskov tiene nada que ver con ello. Java felizmente le permite refinar tipos genéricos cuando hereda una clase. Es por eso que existe la sintaxis y . –

4

Compatibilidad con versiones anteriores.

27

Originalmente se pretendía que Properties fuera de hecho Hashtable<String,String>. Lamentablemente, la implementación de métodos de puente causó un problema. Properties definido de tal manera hace que javac genere métodos sintéticos. Properties debe definir, por ejemplo, un método get que devuelve String pero necesita reemplazar un método que devuelve 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 se extiende Hashtable<Object,Object>. De manera similar, Iterable no devuelve un (solo lectura) SimpleIterable, porque eso habría agregado métodos a las implementaciones Collection.

+2

Buena explicación. Me he preguntado sobre esto también. –

13

Una sola línea (dos-revestimiento para ninguna advertencia) para la creación de Mapa de Propiedades:

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

No responde la pregunta. Pero responde lo que causó la pregunta en primer lugar. Directo al grano. –

+1

¿Es necesario utilizar "tipos de materias primas" aquí? (Al menos en mi IntelliJ IDEA, "sin marcar" es suficiente para suprimir cualquier advertencia). – Jonik

Cuestiones relacionadas