String
jest niezmienny *, ale oznacza to tylko, że nie można go zmienić za pomocą jego publicznego interfejsu API.
To, co tu robisz, to obchodzenie normalnego API za pomocą odbicia. W ten sam sposób możesz zmienić wartości wyliczeń, zmienić tabelę odnośników używaną w autoboksowaniu liczb całkowitych itp.
Powodem s1
i s2
wartością zmiany jest to, że oba odnoszą się do tego samego łańcucha wewnętrznego. Kompilator to robi (jak wspomniano w innych odpowiedziach).
Powodem s3
jest nie był faktycznie nieco zaskakujące dla mnie, jak myślałem, że dzielić value
array ( miało to miejsce w poprzedniej wersji Java , zanim 7u6 Java). Jednak patrząc na kod źródłowy String
, widzimy, że value
tablica znaków dla podłańcucha jest faktycznie kopiowana (za pomocą Arrays.copyOfRange(..)
). Dlatego pozostaje niezmieniony.
Możesz zainstalować SecurityManager
, aby uniknąć złośliwego kodu, aby robić takie rzeczy. Pamiętaj jednak, że niektóre biblioteki zależą od korzystania z tego rodzaju sztuczek refleksyjnych (zazwyczaj narzędzia ORM, biblioteki AOP itp.).
*) Początkowo napisałem, że String
tak naprawdę nie są niezmienne, tylko „skuteczne niezmienne”. Może to wprowadzać w błąd w obecnej implementacji String
, gdzie value
tablica jest rzeczywiście oznaczona private final
. Warto jednak zauważyć, że nie ma sposobu, aby zadeklarować tablicę w Javie jako niezmienną, dlatego należy zachować ostrożność, aby nie ujawniać jej poza klasą, nawet przy odpowiednich modyfikatorach dostępu.
Ponieważ ten temat wydaje się niezwykle popularny, oto kilka sugerowanych lektur: Dyskusja Heinza Kabutza Reflection Madness z JavaZone 2009, która obejmuje wiele problemów w OP, wraz z innymi refleksjami ... cóż ... szaleństwem.
Obejmuje to, dlaczego czasami jest to przydatne. I dlaczego w większości przypadków należy tego unikać. :-)