Zakładając, że nie przeszkadza SecurityManager
ci to zrobić, możesz użyć setAccessible
do obejścia private
i zresetowania modyfikatora, aby się go pozbyć final
i faktycznie zmodyfikować private static final
pole.
Oto przykład:
import java.lang.reflect.*;
public class EverythingIsTrue {
static void setFinalStatic(Field field, Object newValue) throws Exception {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
public static void main(String args[]) throws Exception {
setFinalStatic(Boolean.class.getField("FALSE"), true);
System.out.format("Everything is %s", false); // "Everything is true"
}
}
Zakładając, że nie SecurityException
zostanie wyrzucony, powyższy kod zostanie wydrukowany "Everything is true"
.
To, co faktycznie tutaj zrobiono, wygląda następująco:
- Prymitywne
boolean
wartości true
i false
w main
są autoboxed do typu odniesienia Boolean
„stałych” Boolean.TRUE
iBoolean.FALSE
- Odbicie służy do zmiany
public static final Boolean.FALSE
odniesienia do, Boolean
o którym mowa wBoolean.TRUE
- W rezultacie, za każdym razem, gdy a
false
jest autoboxowane Boolean.FALSE
, odnosi się do tego samegoBoolean
jak ten, zwaną przezBoolean.TRUE
- Wszystko, co było
"false"
teraz, jest"true"
Powiązane pytania
Ostrzeżenia
Za każdym razem, gdy robisz coś takiego, należy zachować szczególną ostrożność. Może nie działać, ponieważ SecurityManager
może być obecny, ale nawet jeśli nie działa, w zależności od wzorca użytkowania może działać lub nie.
JLS 17.5.3 Późniejsza modyfikacja pól końcowych
W niektórych przypadkach, takich jak deserializacja, system będzie musiał zmienić final
pola obiektu po zakończeniu budowy. final
pola można zmieniać za pomocą refleksji i innych środków zależnych od implementacji. Jedyny wzorzec, w którym ma to rozsądną semantykę, to taki, w którym obiekt jest konstruowany, a następnie final
pola obiektu są aktualizowane. Obiekt nie powinien być widoczny dla innych wątków, a final
pola nie powinny być odczytywane, dopóki wszystkie aktualizacje final
pól obiektu nie zostaną zakończone. Zamrożenie final
pola występuje zarówno na końcu konstruktora, w którym final
pole jest ustawione, jak i natychmiast po każdej modyfikacji final
pola poprzez odbicie lub inny specjalny mechanizm.
Nawet wtedy istnieje wiele komplikacji. Jeśli final
pole zostanie zainicjowane do stałej czasu kompilacji w deklaracji pola, zmiany w final
polu mogą nie zostać zaobserwowane, ponieważ użycie tego final
pola jest zastępowane w czasie kompilacji stałą czasu kompilacji.
Innym problemem jest to, że specyfikacja pozwala na agresywną optymalizację final
pól. W obrębie wątku dopuszcza się zmianę kolejności odczytów final
pola z tymi modyfikacjami pola końcowego, które nie mają miejsca w konstruktorze.
Zobacz też
- JLS 15.28 Wyrażenie stałe
- Jest mało prawdopodobne, aby ta technika działała z prymitywem
private static final boolean
, ponieważ jest ona nieodłączna jako stała czasowa kompilacji, a zatem „nowa” wartość może nie być obserwowalna
Dodatek: o manipulacji bitowej
Głównie,
field.getModifiers() & ~Modifier.FINAL
wyłącza bit odpowiadający Modifier.FINAL
od field.getModifiers()
. &
jest bitowo-i, i ~
jest bit-dopełniaczem.
Zobacz też
Pamiętaj o stałych wyrażeniach
Nadal nie jesteś w stanie rozwiązać tego ?, popadłeś w depresję tak jak ja? Czy twój kod wygląda tak?
public class A {
private final String myVar = "Some Value";
}
Czytając komentarze do tej odpowiedzi, szczególnie tej autorstwa @Pshemo, przypomniałem sobie, że Wyrażenia stałe są obsługiwane inaczej, więc nie będzie można ich modyfikować. Dlatego musisz zmienić kod, aby wyglądał następująco:
public class A {
private final String myVar;
private A() {
myVar = "Some Value";
}
}
jeśli nie jesteś właścicielem klasy ... Czuję cię!
Aby uzyskać więcej informacji o tym, dlaczego to zachowanie czyta to ?