Je mehr ich über die Kraft von gelernt habe java.lang.reflect.AccessibleObject.setAccessible
, desto mehr staune ich darüber, was sie bewirken kann. Dies wird aus meiner Antwort auf die Frage ( Verwenden von Reflection zum Ändern der statischen endgültigen File.separatorChar für Unit-Tests ) angepasst .
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"
}
}
Sie können wirklich unerhörte Dinge tun:
public class UltimateAnswerToEverything {
static Integer[] ultimateAnswer() {
Integer[] ret = new Integer[256];
java.util.Arrays.fill(ret, 42);
return ret;
}
public static void main(String args[]) throws Exception {
EverythingIsTrue.setFinalStatic(
Class.forName("java.lang.Integer$IntegerCache")
.getDeclaredField("cache"),
ultimateAnswer()
);
System.out.format("6 * 9 = %d", 6 * 9); // "6 * 9 = 42"
}
}
Vermutlich erkennen die API-Designer, wie missbräuchlich sein setAccessible
kann, müssen aber eingeräumt haben, dass es legitime Verwendungszwecke hat, um es bereitzustellen. Meine Fragen sind also:
- Wofür sind die wirklich legitimen Verwendungszwecke
setAccessible
?- Könnte Java so konzipiert sein, dass es dieses Bedürfnis überhaupt nicht hat?
- Was wären die negativen Konsequenzen (wenn überhaupt) eines solchen Designs?
- Können Sie sich nur
setAccessible
auf legitime Verwendungen beschränken?- Ist es nur durch
SecurityManager
?- Wie funktioniert es? Whitelist / Blacklist, Granularität usw.?
- Ist es üblich, dass Sie es in Ihren Anwendungen konfigurieren müssen?
- Kann ich meine Klassen
setAccessible
unabhängig von derSecurityManager
Konfiguration so schreiben, dass sie sicher sind?- Oder bin ich dem ausgeliefert, der die Konfiguration verwaltet?
- Ist es nur durch
Ich denke, eine weitere wichtige Frage ist: MUSS ICH SICH UM DIESE SORGEN ???
Keine meiner Klassen hat den Anschein einer durchsetzbaren Privatsphäre. Das Singleton-Muster (Zweifel an seinen Vorzügen beiseite lassen) kann jetzt nicht mehr durchgesetzt werden. Wie meine obigen Ausschnitte zeigen, sind selbst einige grundlegende Annahmen darüber, wie Java Fundamental funktioniert, nicht annähernd garantiert.
SIND DIESE PROBLEME NICHT WIRKLICH ???
Okay, ich habe gerade bestätigt: Dank setAccessible
sind Java-Strings NICHT unveränderlich.
import java.lang.reflect.*;
public class MutableStrings {
static void mutate(String s) throws Exception {
Field value = String.class.getDeclaredField("value");
value.setAccessible(true);
value.set(s, s.toUpperCase().toCharArray());
}
public static void main(String args[]) throws Exception {
final String s = "Hello world!";
System.out.println(s); // "Hello world!"
mutate(s);
System.out.println(s); // "HELLO WORLD!"
}
}
Bin ich der einzige, der das für ein RIESIGES Problem hält?