52 votes

Pourquoi java.util.Properties implémente Map<Object,Object> et non Map<String,String> ?

El java.util.Properties est destinée à représenter une carte dont les clés et les valeurs sont toutes deux des chaînes. Cela est dû au fait que Properties sont utilisés pour lire .properties qui sont des fichiers texte.

Alors, pourquoi dans Java 5 ont-ils modifié cette classe pour implémenter Map<Object,Object> et non Map<String,String> ?

El javadoc estados:

Comme Properties hérite de Hashtable, les méthodes put et putAll peuvent être appliquées à un objet Properties. Leur utilisation est fortement déconseillée car elles permettent à l'appelant d'insérer des entrées dont les clés ou les valeurs ne sont pas des chaînes de caractères. La méthode setProperty doit être utilisée à la place. Si la méthode store ou save est appelée sur un objet Properties "compromis" qui contient une clé ou une valeur autre qu'une chaîne de caractères, l'appel échouera.

Puisque les clés et les valeurs sont censées être des chaînes de caractères, pourquoi ne pas le faire respecter de manière statique en utilisant le type générique approprié ?

Je suppose que faire Properties mettre en œuvre Map<String,String> ne serait pas entièrement rétrocompatible avec le code écrit pour la version pré-Java 5. Si vous avez un code plus ancien qui insère des chaînes de caractères dans un objet Properties, ce code ne compilera plus avec Java 5. Mais... n'est-ce pas une bonne chose ? Le but des génériques n'est-il pas d'attraper de telles erreurs de type au moment de la compilation ?

53voto

Marcus Downing Points 5250

Parce qu'ils l'ont fait dans l'urgence aux premiers jours de Java, et n'ont pas réalisé quelles seraient les implications quatre versions plus tard.

Les génériques étaient censés faire partie de la conception de Java dès le début, mais cette fonctionnalité a été abandonnée car elle était trop compliquée et, à l'époque, inutile. En conséquence, une grande partie du code des bibliothèques standard est écrite en supposant l'existence de collections non génériques. Il a fallu le prototype de langage "Pizza" de Martin Odersky pour montrer qu'il était possible de les réaliser assez bien tout en maintenant une compatibilité ascendante presque parfaite, tant avec le code Java qu'avec le bytecode. Le prototype a conduit à Java 5, dans lequel les classes de collections ont été équipées de génériques de manière à ce que l'ancien code puisse continuer à fonctionner.

Malheureusement, s'ils devaient rendre rétroactivement Properties hériter de Map<String, String> alors le code suivant, précédemment valide, cesserait de fonctionner :

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

Je ne comprends pas pourquoi quelqu'un ferait cela, mais l'engagement de Sun en faveur de la rétrocompatibilité de Java a dépassé le stade de l'héroïsme pour devenir inutile.

Ce qui est maintenant apprécié par la plupart des observateurs instruits est que Properties n'aurait jamais dû hériter de Map du tout. Il devrait plutôt s'enrouler autour de Map en n'exposant que les caractéristiques de la carte qui ont un sens.

Après avoir réinventé Java, Martin Odersky a créé le nouveau langage Scala, qui est plus propre, hérite de moins d'erreurs et innove dans de nombreux domaines. Si vous trouvez les défauts de Java ennuyeux, jetez-y un coup d'œil.

27voto

Il était initialement prévu que Properties s'étendrait en effet Hashtable<String,String> . Malheureusement, la mise en œuvre des méthodes de pontage a posé un problème. Properties défini de telle manière fait que javac génère des méthodes synthétiques. Properties devrait définir, par exemple, une get qui renvoie un String mais doit remplacer une méthode qui renvoie Object . Une méthode de pont synthétique est donc ajoutée.

Supposons que vous ayez une classe écrite dans le bon vieux temps de la version 1.4. Vous avez surchargé certaines méthodes dans Properties . Mais ce que vous n'avez pas fait, c'est surcharger les nouvelles méthodes. Cela conduit à un comportement involontaire. Pour éviter ces méthodes de pontage, Properties étend Hashtable<Object,Object> . De même, Iterable ne renvoie pas un fichier (en lecture seule) SimpleIterable car cela aurait ajouté des méthodes à Collection mises en œuvre.

13voto

Spajus Points 3296

Une ligne simple (deux lignes pour ne pas avoir d'avertissement) pour créer une carte à partir de propriétés :

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

4voto

KitsuneYMG Points 7604

Rétrocompatibilité.

2voto

Michael Borgwardt Points 181658

La raison : Principe de substitution de Liskov et la rétrocompatibilité. Properties étend Hashtable et doit donc accepter tous les messages que Hashtable accepterait - et cela signifie accepter put(Object, Object) . Et il doit s'étendre à la plaine Hashtable au lieu de Hashtable<String, String> parce que les génériques ont été implémentés de manière compatissante vers le bas via effacement de type Donc, une fois que le compilateur a fait son travail, il n'y a pas de génériques.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X