Die ursprüngliche Geschichte ist dieser Artikel über StackOverflow JavaScript. https://stackoverflow.com/questions/48270127/can-a-1-a-2-a-3-ever-evaluate-to-true
Wie ein Samen offenbart, ** Wenn Sie die implizite Typkonvertierung in JavaScript überschreiben und die Verarbeitung dort ablegen, können Sie sie zum Zeitpunkt des Vergleichs ausführen! ** ** ** Deshalb können Sie mit Java arbeiten, wenn Sie es mit der geerbten Klasse überschreiben!
Lassen Sie uns für alle Fälle die implizite Typkonvertierung von Java überprüfen.
@Test
public void test_integer() {
Integer a = Integer.valueOf(1);
if(a == 1){
System.out.println("true");
}
}
Dies wird verglichen, indem beim Vergleich mit int "intValue ()" von "Integer" aufgerufen wird. In Java heißt es Unboxing.
Fehlgeschlagen, da die Integer-Klasse endgültig ist und nicht überschrieben werden kann Oder besser gesagt, wenn Sie den intValue von Integer überschreiben, sterben Sie auf verschiedene Weise.
Erstellen wir also eine numerische Klasse, indem wir die Number-Klasse erben, die die übergeordnete abstrakte Klasse von Integer ist.
public class StrangeObject extends Number implements Comparable<Integer>{
private int value;
public StrangeObject(int value){
this.value = value;
}
@Override
public int intValue() {
value++;
return value;
}
@Override
public long longValue() {
value++;
return value;
}
@Override
public float floatValue() {
value++;
return value;
}
@Override
public double doubleValue() {
value++;
return value;
}
public int compareTo(Integer outerValue) {
return (value < outerValue) ? -1 : ((value == outerValue) ? 0 : 1);
}
}
Da habe ich intValue () implementiert und auch die Schnittstelle von Comparable
@Test
public void test_a1a2a3() throws Exception {
StrangeObject a = new StrangeObject(0);
if(a == 1 && a == 2 && a == 3){
System.out.println("true");
}
}
Error:(22, 14) java:Die Typen StrangeObject und int können nicht verglichen werden
Es ist sinnlos, den Typ vor dem Vergleich zu überprüfen ...
@Test
public void test_a1a2a3() throws Exception {
StrangeObject a = new StrangeObject(0);
if(a.intValue() == 1 && a.intValue() == 2 && a.intValue() == 3){
System.out.println("true");
}
}
Dies funktioniert, aber was soll ich tun, um intValue () zu entfernen (implizit auszuführen)?
Von hier an wird die Dunkelheit ziemlich tief sein, also lasst es uns einfach überprüfen.
Da im Kommentar darauf hingewiesen wurde, dass es nicht entpackt wird, es sei denn, es ist in einigen Systemklassen Schreiben Sie die Systemklasse neu.
Verwenden Sie Javassist, um die Integer-Klassendatei neu zu schreiben.
Im Fall einer Systemklasse kann sie zur Laufzeit nicht neu geschrieben werden Es spuckt einmal als statische Datei aus und liest die neu geschriebene Datei zur Laufzeit.
@Test
public void testIntegerExport() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("java.lang.Integer");
CtMethod method = cc.getDeclaredMethod("intValue");
//Wert in intValue++Hinzugefügt
method.insertBefore("value++;");
//Geben Sie die geänderte Klassendatei aus
cc.writeFile();
}
Wenn Sie diese Testmethode ausführen, wird die neu geschriebene Integer-Klasse an . / Java / lang / Integer.class
ausgegeben.
Erstellen Sie dann die folgende Hauptklasse.
public class A123 {
public static void main(String[] args){
Integer a = Integer.valueOf(0);
if(a == 1 && a == 2 && a == 3){
System.out.println(true);
}
}
}
Für Laufzeitargumente
Fügen Sie -Xbootclasspath / p :.
hinzu.
Dadurch wird die geänderte Integer-Klasse geladen.
Wenn Sie diese Klasse jedoch laden
java.lang.InternalError
- klass: 'java/lang/InternalError'
#
# A fatal error has been detected by the Java Runtime Environment:
#
...
Es kann wahrscheinlich nicht ausgeführt werden, da der Wert von Integer schwankt, wenn die JVM ausgeführt wird.
Also werde ich die Integer-Datei weiter modifizieren.
Machen Sie es zu einer Integer-Klasse, die vom Beginn der VM-Ausführung bis zur Ausführung der Hauptklasse normal funktioniert.
@Test
public void testIntegerExport2() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("java.lang.Integer");
CtMethod m = cc.getDeclaredMethod("intValue");
//Habe eine Flagge drinnen
CtField isBroken = new CtField(CtClass.booleanType, "isBroken", cc);
isBroken.setModifiers(Modifier.PUBLIC);
cc.addField(isBroken, CtField.Initializer.constant(false));
//Nur hinzufügen, wenn das Flag aktiviert ist
m.insertBefore("if(isBroken) value++;");
//Geben Sie die geänderte Klassendatei aus
cc.writeFile();
}
Hinzufügen der Flag-Änderungsverarbeitung zur Hauptklasse.
public class A123 {
public static void main(String[] args) {
Integer a = Integer.valueOf(0);
try {
//Schreiben Sie isBroken mit Reflection neu, um Kompilierungsfehler zu vermeiden
Integer.class.getField("isBroken").setBoolean(a, true);
if (a == 1 && a == 2 && a == 3) {
System.out.println(true);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
Wenn Sie versuchen, den Wert für isBroken of Integer zu ändern Wenn Sie es normal umschreiben, ist das Feld nicht vorhanden Ich erhalte einen Kompilierungsfehler. Daher tritt beim Umschreiben mit Reflektion ein Laufzeitfehler auf, wenn er nicht vorhanden ist. Sie können den Schrecken der Reflexion sehen ...
Ausführungsergebnis
Wenn Sie dem Laufzeitargument -Xbootclasspath / p :.
hinzufügen und ausführen,
true
Ich konnte (a == 1 && a == 2 && a == 3)
in Java erfolgreich in true
ändern.
Recommended Posts