2015-05-21 9 views
12

Ich versuche zu verstehen, warum java.util.Properties auf diese Weise implementiert wurde. Es hat zwei Schnittstellen: getProperty/setProperty, die nur Zeichenfolgen akzeptiert, und put/get, die jedes Objekt als Wert akzeptiert. Diese beiden Schnittstellen scheinen sich zu überlappen, sodass eine mit put() hinzugefügte Zeichenfolge mit getProperty() abgerufen werden kann.Setzen von Objekten in java.util.Properties

Es scheint einige Probleme mit dieser seltsamen hybriden Schnittstelle zu geben. Das Setzen eines Objekts, das eine Zeichenfolgeneigenschaft überschreibt, hat den Nebeneffekt, dass der Zeichenfolgenwert gelöscht wird, wodurch null als getProperty-Ergebnis erzeugt wird. Das Hinzufügen einer Ganzzahl oder eines anderen Werts, der eine einfache Zeichenfolgenübersetzung enthält, wird möglicherweise als echter Eigenschaftswert missverstanden (aber als Eigenschaft ist es immer null).

Meine Frage ist: Gibt es einen wirklichen, praktischen Grund dafür? Oder ist es eine halbfertige Implementierung, wie ich vermute?

+0

Ich kann es nicht sichern, aber ich würde stark vermuten, dass das Problem Rückwärtskompatibilität ist. 'Properties' erweitert' Hashtable', was eine alte Klasse von vor Generics ist; das heißt, wenn Sie eine 'Eigenschaft' hätten, könnten Sie' property.put (was auch immer, was auch immerElse) 'hineingerufen haben. Als Generika kamen, wollten die Java-Leute den Code rückwärtskompatibel halten, was bedeutete, dass er 'Hashtable ' erweitern musste. – yshavit

+0

'Properties' ist eine Unterklasse von' Hashtable', mit keiner Übersteuerung von 'get' /' put', daher das Verhalten. 'getProperty' /' setProperty' sind getippte Versionen von 'get' /' put'. Es ist eine Frage der Geschichte und nicht des Versteckens. –

Antwort

10

Joshua Bloch dies in Effective Java

[aus Kapitel 4] Im Fall von Properties ausdrücklich erwähnt, beabsichtigt die Designer, dass nur Strings als Schlüssel und Werte erlaubt, aber den direkten Zugriff auf das darunter liegende Hashtable erlaubt diese Invariante wird verletzt. Sobald diese Invariante verletzt wird, ist es nicht länger möglich, andere Teile der Eigenschaften-API zu verwenden (load und store). Als dieses Problem entdeckt wurde, war es zu spät, es zu korrigieren, da Clients von der Verwendung von Nichtstringschlüsseln und -werten abhängig waren.

Dieser Text steht im Kontext der Verwendung von Komposition über Vererbung. Er verwendet dies im Grunde als ein Beispiel dafür, wann die Komposition anstelle der Vererbung verwendet werden sollte. Wenn Properties eine Map statt einer erweitern, könnte es die Invariante von String als Schlüssel und Werte erzwungen haben.

Die Antwort ist also: Es war ein Versehen.

+1

Wählen Sie diese Antwort, weil es erklärt, warum es auf diese Weise implementiert wurde, mehr als nur "nicht die anderen Methoden verwenden". Als Nebenbemerkung verwendet die Java-Mail-API dies zum Konfigurieren einer benutzerdefinierten SSL-Socket-Factory. Oh java, die Hassliebe, die wir haben. –

2

Offizielle Dokumentationen sagt

Da Eigenschaften von Hashtable erbt, kann der Put und putAll Methoden auf ein Properties-Objekt angewendet werden. Von ihrer Verwendung wird dringend abgeraten, da sie es dem Aufrufer ermöglichen, Einträge einzugeben, deren Schlüssel oder Werte keine Zeichenfolgen sind. Die setProperty-Methode sollte stattdessen verwendet werden. Wenn die Speicher- oder Speichermethode für ein "kompromittiertes" Properties-Objekt aufgerufen wird, das einen Nicht-String-Schlüssel oder Wert enthält, schlägt der Aufruf fehl. Auf ähnliche Weise schlägt der Aufruf der Methode propertyNames oder list fehl, wenn er für ein "kompromittiertes" Properties-Objekt aufgerufen wird, das einen Nicht-String-Schlüssel enthält.

http://docs.oracle.com/javase/8/docs/api/java/util/Properties.html

5

Zugang zu put und get ist ein Ergebnis der Properties eine Erweiterung von Hashtable zu sein, und die beiden Verfahren nicht verwendet werden sollen (aber nicht von der Implementierung in der übergeordneten Klasse aufgrund ihres öffentlichen Zugang versteckt werden).

Die Javadocs haben eine nette Notiz, warum Sie nicht diese Methoden, und sollte stattdessen nur Verwendung Strings verwenden sollten:

Da Properties erbt von Hashtable, die put und putAll Methoden können auf eine Properties angewendet werden Objekt. Von ihrer Verwendung wird dringend abgeraten, da sie es dem Aufrufer ermöglichen, Einträge einzugeben, deren Schlüssel oder Werte nicht Strings sind. Die Methode setProperty sollte stattdessen verwendet werden. Wenn die Methode store oder save für ein "kompromittiertes" Objekt Properties aufgerufen wird, das einen Schlüssel oder Wert ungleich String enthält, schlägt der Aufruf fehl. Ebenso wird der Aufruf an die propertyNames oder list Methode fehlschlagen, wenn es auf einem "kompromittierten" Properties Objekt aufgerufen wird, das einen nicht String Schlüssel enthält.

Wie @yshavit bemerkt, würde es mehr Sinn für Properties macht Hashtable<String, String> als eine Hash-Tabelle von zwei Objekten zu erweitern, aber das war wahrscheinlich eine Entscheidung getroffen, um die Rückwärtskompatibilität, wie alle Programme get/put mit jeder Verwendung Nicht-String-Objekte wären durch eine solche Änderung gebrochen worden.

+0

Aber das geht nicht auf einen entscheidenden Teil der Frage ein, weshalb die get/put-Methoden auf "Object" statt auf "String" wirken.Das heißt, warum wird 'Hashtable ' nicht erweitert? (Per meinem Kommentar oben, ich vermute stark, dass es für die Rückwärtskompatibilität ist - aber ich habe keine spezifischen Beweise.) – yshavit

+0

@yshavit Gute Anmerkung; Ich stimme zu, dass es fast ausnahmslos rückwärtskompatibel ist, und ich habe eine solche Notiz in die Antwort aufgenommen. – Vulcan

0

Vom Java Docs

Da Eigenschaften von Hashtable erbt, der Put und putAll Methoden auf ein Properties-Objekt angewendet werden.Ihre Verwendung ist stark entmutigt, da sie dem Anrufer erlauben, Einträge, deren Schlüssel oder Werte sind keine Strings. Die setProperty-Methode sollte stattdessen verwendet werden. Wenn die Speicher- oder Speichermethode für ein "kompromittiertes" Eigenschaftenobjekt aufgerufen wird, das einen Nicht-String-Schlüssel oder -Wert enthält, schlägt der Aufruf fehl. In ähnlicher Weise schlägt der Aufruf der Methode propertyNames oder list fehl, wenn für ein "kompromittiertes" Properties-Objekt aufgerufen wird, das einen Nicht-String-Schlüssel enthält.

0

Properties erstreckt Hashtable, so können Sie verwenden Properties überall können Sie eine Hashtable verwenden.

Die Hashtable Klasse ist, wo die get() und put() Funktionen herkommen.

0

put(key, value) und get(key) sind Reste einer fragwürdigen Entscheidung zu Properties extend Hashtable zurück in den Tag zu haben. Dieses Verhalten kann nicht geändert werden, da es die Abwärtskompatibilität beeinträchtigt, aber jeder halbwegs anständige Styleguide, einschließlich der API-Dokumentation selbst, wird empfehlen, diese Methoden niemals zu verwenden.

0

Wie andere schon gesagt haben, soll es nur für Strings verwendet werden. Es gibt Möglichkeiten, ein Objekt als String zu serialisieren und abzurufen, aber offensichtlich ist das nicht dafür gedacht. Ich verstehe, dass es wirklich nervig ist, da es so nah wie möglich an einer plattformübergreifenden Methode zum Speichern und Abrufen von App-Daten ist. Soweit ich weiß, gibt es keine offizielle Möglichkeit, andere Dinge als Strings in einem Ordner zu speichern, der vor dem Benutzer verborgen ist, obwohl die meisten Betriebssysteme appdata-Verzeichnisse haben.

Verwandte Themen