2015-05-21 12 views
12

Próbuję zrozumieć, dlaczego java.util.Properties została zaimplementowana w ten sposób. Ma dwa interfejsy: getProperty/setProperty, które akceptuje tylko łańcuchy i put/get, które akceptuje dowolny obiekt jako wartość. Te dwa interfejsy wydają się nakładać, więc ciąg dodany za pomocą funkcji put() może zostać pobrany za pomocą metody getProperty().Umieszczanie obiektów w java.util.Properties

Wygląda na to, że z tym dziwnym interfejsem hybrydowym występują pewne problemy. Umieszczenie obiektu, który przesłania właściwość ciągu, powoduje efekt uboczny usuwania wartości ciągu, tworząc wartość null jako wynik getProperty. Dodanie liczby całkowitej lub innej wartości, która ma proste tłumaczenie ciągu znaków, może być źle rozumiane jako wartość nieruchomości (ale jako właściwość zawsze ma wartość NULL).

Moje pytanie brzmi: czy istnieje prawdziwy, praktyczny powód tego? A może jest to na wpół wypalona implementacja, jak podejrzewam?

+0

Nie mogę tego zrobić, ale podejrzewam, że problem jest zgodny wstecz. 'Właściwości' rozszerza' HashTable', która jest starą klasą przed wcześniejszymi rodzajami; oznacza to, że gdybyś miał "Właściwości", mógłbyś wywołać w nim 'properties.put (cokolwiek, niezależnieElse). Gdy pojawiły się generyczne, członkowie Java chcieli zachować kompatybilność wsteczną kodu, co oznaczało rozszerzenie "Hashtable ". – yshavit

+0

'Właściwości' jest podklasą' HashTable', bez nadpisywania 'get' /' put', stąd zachowanie. 'getProperty' /' setProperty' to typowane wersje 'get' /' put'. To kwestia historii i nie chowania się. –

Odpowiedz

10

Joshua Bloch wspomina o tym wyraźnie w Effective Java

[rozdziału 4] W przypadku Properties projektanci zamierzeniu jedynie ciągi zostać dopuszczone klucze i wartości, ale bezpośredni dostęp do leżącej Hashtable pozwala ten niezmiennik, który zostanie naruszony. Po naruszeniu tego niezmiennika nie można już korzystać z innych części interfejsu API właściwości (load i store). Do czasu znalezienia tego problemu było już za późno, aby go poprawić, ponieważ klienci polegali na użyciu kluczy i wartości nie związanych.

Ten tekst dotyczy kontekstu używania kompozycji nad dziedziczeniem. Zasadniczo używa tego jako przykładu, kiedy należy używać kompozycji zamiast dziedziczenia. Jeśli Properties owinąłby jeden Map zamiast jednego, mógłby wymusić nieuruchomienie użycia String jako kluczy i wartości.

Tak więc odpowiedź brzmi: To było przeoczenie.

+1

Wybierając tę ​​odpowiedź, ponieważ wyjaśnia, dlaczego została ona wdrożona w ten sposób, więcej niż "nie stosuj innych metod". Na marginesie, interfejs API poczty java używa tego projektu do projektowania niestandardowej fabryki gniazd SSL. Och, java, związek miłości i nienawiści, jaki mamy. –

2

Oficjalne dokumentacje mówi

Ponieważ właściwości dziedziczy z Hashtable, put i metody putAll można zastosować do obiektu Właściwości. Ich użycie jest zdecydowanie odradzane, ponieważ pozwalają wywołującym wstawiać wpisy, których kluczami lub wartościami nie są łańcuchy. Zamiast tego należy użyć metody setProperty. Jeśli metoda przechowywania lub składowania jest wywoływana w obiekcie "zagrożonym" właściwości, który zawiera klucz lub wartość inną niż String, wywołanie zakończy się niepowodzeniem. Podobnie wywołanie metody propertyNames lub list nie powiedzie się, jeśli zostanie wywołane w obiekcie "zagrożonym" właściwości, który zawiera klucz inny niż String.

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

5

Dostęp do put i get jest wynikiem Properties będąc przedłużeniem Hashtable, a dwie metody nie powinny być używane (ale nie może być ukryte z realizacji ze względu na ich publicznego dostępu w nadrzędnej).

Javadocs miłego notatkę o tym, dlaczego nie powinno się stosować te same metody i powinno zamiast tylko używać łańcuchów:

Ponieważ Properties dziedziczy z Hashtable sposoby put i putAll mogą być stosowane do Properties obiekt. Ich użycie jest zdecydowanie odradzane, ponieważ pozwalają wywołującemu wstawiać wpisy, których klucze lub wartości nie są Strings. Zamiast tego należy użyć metody setProperty. Jeśli metoda store lubzostanie wywołana w "zagrożonym" obiekcie o wartości Properties, który zawiera klucz lub wartość innego niż , wywołanie zakończy się niepowodzeniem. Podobnie wywołanie metody propertyNames lub list nie powiedzie się, jeśli zostanie wywołane na "zagrożonym" obiekcie o nazwie Properties, który zawiera klucz inny niż String.

Jak @yshavit zauważa, że ​​to więcej sensu dla Properties przedłużyć Hashtable<String, String> niż hashtable dwóch obiektów, ale to było prawdopodobnie decyzja podjęta w celu utrzymania kompatybilności wstecznej, jak wszelkie programy używając get/put z dowolnego obiekty inne niż String zostałyby uszkodzone przez taką zmianę.

+0

Ale to nie rozwiązuje kluczowej części pytania, dlatego metody get/put działają na 'Object' zamiast' String'.To znaczy, dlaczego nie rozszerza 'Hashtable '? (Zgodnie z powyższym komentarzem, mocno podejrzewam, że jest to kompatybilność wsteczna - ale nie mam konkretnych dowodów.) – yshavit

+0

@yshavit Dobra uwaga; Zgadzam się, że jest to prawie na pewno kompatybilność wsteczna i dodałem taką notatkę do odpowiedzi. – Vulcan

0

Z Java Docs

Ponieważ właściwości dziedziczy z Hashtable, put i metod putAll można zastosować do obiektu Właściwości.Ich użycie jest odradzane, ponieważ pozwalają wywołującemu wstawiać wpisy, których klucze lub wartości nie są ciągami. Zamiast tego należy użyć metody setProperty. Jeśli metoda przechowywania lub składowania zostanie wywołana na obiekcie "zagrożonym" Właściwości: , który zawiera klucz lub wartość inną niż String, wywołanie zakończy się niepowodzeniem. W podobny sposób wywołanie metody propertyNames lub listy nie powiedzie się, jeśli zostanie wywołane w obiekcie "zagrożonym" właściwości, który zawiera klucz inny niż String, o numerze: .

0

Properties rozciąga Hashtable, dzięki czemu można używać Properties wszędzie można użyć Hashtable.

Klasa Hashtable to miejsce, z którego pochodzą funkcje get() i put().

0

put(key, value) i get(key) są resztą wątpliwej decyzji o przedłużeniu PropertiesHashtable. To zachowanie nie może być zmienione, ponieważ złamie kompatybilność wsteczną, ale jakikolwiek przyzwoity przewodnik po stylach, w tym sam dokumentacja API, zaleci, aby nigdy nie używać tych metod.

0

Jak powiedzieli inni, należy go używać tylko dla Strings. Istnieją sposoby serializacji obiektu jako łańcucha znaków i jego pobierania, ale oczywiście nie jest to przeznaczone do tego celu. Rozumiem, że to naprawdę denerwujące, ponieważ jest najbliżej tego, jak można uzyskać wieloplatformowy sposób zapisywania i pobierania danych aplikacji. O ile mi wiadomo, nie ma oficjalnego sposobu na zapisywanie rzeczy innych niż ciągi w folderze, który jest ukryty przed użytkownikiem, mimo że większość systemów operacyjnych ma katalogi appdata.