Wyobraź sobie, że mam tę klasę:
public class Test
{
private String[] arr = new String[]{"1","2"};
public String[] getArr()
{
return arr;
}
}
Teraz mam inną klasę, która używa powyższej klasy:
Test test = new Test();
test.getArr()[0] ="some value!"; //!!!
Oto więc problem: uzyskałem dostęp do prywatnego pola klasy z zewnątrz! Jak mogę temu zapobiec? Mam na myśli, jak mogę uczynić tę tablicę niezmienną? Czy to oznacza, że każdą metodą pobierającą możesz wypracować sobie drogę do uzyskania dostępu do pola prywatnego? (Nie chcę żadnych bibliotek, takich jak Guava. Muszę tylko wiedzieć, jak to zrobić).
final
robi uniemożliwić modyfikację tej dziedzinie . Jednak zapobieżenie modyfikacji tego, do któregoObject
odwołuje się pole, jest bardziej skomplikowane.Odpowiedzi:
Musisz zwrócić kopię swojej tablicy.
źródło
Unmodifiable List
.Jeśli możesz użyć listy zamiast tablicy, Kolekcje udostępnia niemodyfikowalną listę :
źródło
Collections.unmodifiableList(list)
jako przypisanie do pola, aby upewnić się, że lista nie zostanie zmieniona przez samą klasę.String
jest, ale jeśli są zmienne, może być konieczne zrobienie czegoś, aby uniemożliwić wywołującemu ich zmianę.Modyfikator
private
chroni tylko samo pole przed dostępem z innych klas, ale nie chroni odniesienia do obiektów przez to pole. Jeśli chcesz chronić obiekt, do którego istnieje odniesienie, po prostu go nie udostępniaj. Zmianado:
lub
źródło
O
Collections.unmodifiableList
tym już zostało wspomniane - oArrays.asList()
dziwo nie! Moim rozwiązaniem byłoby również użycie listy z zewnątrz i zawinięcie tablicy w następujący sposób:Problem z kopiowaniem tablicy polega na tym, że jeśli robisz to za każdym razem, gdy uzyskujesz dostęp do kodu, a tablica jest duża, na pewno stworzysz dużo pracy dla garbage collectora. Tak więc kopiowanie jest prostym, ale bardzo złym podejściem - powiedziałbym „tanie”, ale drogie w pamięci! Zwłaszcza, gdy masz więcej niż tylko 2 elementy.
Jeśli spojrzeć na kod źródłowy
Arrays.asList
iCollections.unmodifiableList
jest faktycznie niewiele utworzony. Pierwsza po prostu zawija tablicę bez jej kopiowania, druga po prostu zawija listę, uniemożliwiając jej zmiany.źródło
immutableList
do końca!Arrays.asList
iCollections.unmodifiableList
są prawdopodobnie tańsze w przypadku większych tablic. Może ktoś może obliczyć, ile elementów jest potrzebnych, ale widziałem już kod w pętlach for z tablicami zawierającymi tysiące elementów kopiowanych tylko po to, aby zapobiec modyfikacji - to szaleństwo!Możesz także użyć tego,
ImmutableList
co powinno być lepsze niż standardoweunmodifiableList
. Klasa jest częścią bibliotek Guava, które zostały utworzone przez Google.Oto opis:
Oto prosty przykład, jak go używać:
źródło
Test
klasie, która pozostawi zwróconą listę niezmienioną . Musisz się upewnić, żeImmutableList
zostanie zwrócony i że elementy listy są również niezmienne. W przeciwnym razie moje rozwiązanie również powinno być bezpieczne.z tego punktu widzenia powinieneś użyć kopii tablicy systemowej:
źródło
clone
i nie jest tak zwięzły.Możesz zwrócić kopię danych. Dzwoniący, który zdecyduje się zmienić dane, zmieni tylko kopię
źródło
Istotą problemu jest to, że zwracasz wskaźnik do zmiennego obiektu. Ups. Albo wyrenderujesz obiekt jako niezmienny (rozwiązanie listy niemodyfikowalnej), albo zwrócisz kopię obiektu.
Ogólnie rzecz biorąc, ostateczność obiektów nie chroni przed zmianą obiektów, jeśli są one zmienne. Te dwa problemy to „całowanie kuzynów”.
źródło
Zwrócenie niemodyfikowalnej listy to dobry pomysł. Ale lista, która jest niemodyfikowalna podczas wywołania metody pobierającej, może być nadal zmieniana przez klasę lub klasy, które są pochodnymi klasy.
Zamiast tego powinieneś jasno powiedzieć każdemu, kto rozszerza klasę, że lista nie powinna być modyfikowana.
W twoim przykładzie może to prowadzić do następującego kodu:
W powyższym przykładzie utworzyłem plik
STRINGS
upubliczniłem pole, w zasadzie możesz pozbyć się wywołania metody, ponieważ wartości są już znane.Możesz także przypisać ciągi do
private final List<String>
pola, którego nie można modyfikować podczas konstruowania instancji klasy. Użycie argumentów stałych lub argumentów instancji (konstruktora) zależy od projektu klasy.źródło
Tak, powinieneś zwrócić kopię tablicy:
źródło