The original story is this article on StackOverflow JavaScript. https://stackoverflow.com/questions/48270127/can-a-1-a-2-a-3-ever-evaluate-to-true
As a seed reveal, ** If you override the implicit type conversion in JavaScript and put the processing there, you can execute it at the time of comparison! ** ** That's why you can go with Java if you override it with the inherited class!
Just in case, let's check Java's implicit type conversion.
@Test
public void test_integer() {
Integer a = Integer.valueOf(1);
if(a == 1){
System.out.println("true");
}
}
This is compared by calling ʻintValue () of ʻInteger
when comparing with int.
In Java, it's called unboxing.
Failed because the Integer class is final and cannot be overridden Or rather, if you override the intValue of Integer, you will die in various ways.
So, let's create a numeric class by inheriting the Number class, which is the abstract class of the parent of Integer.
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);
}
}
Since I implemented intValue () and also implemented the interface of 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:Types StrangeObject and int cannot be compared
It's useless to check the type before comparison ...
@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");
}
}
This works, but what should I do to remove (implicitly execute) intValue ()?
From here onward, the darkness will be quite deep, so let's just check it.
Since it was pointed out in the comment that it will not be unboxed unless it is in some system classes Rewrite the system class.
Use Javassist to rewrite the Integer class file.
In the case of system class, it cannot be rewritten at runtime, so It is spit out as a static file once, and the rewritten file is read at runtime.
@Test
public void testIntegerExport() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("java.lang.Integer");
CtMethod method = cc.getDeclaredMethod("intValue");
//value in intValue++Added
method.insertBefore("value++;");
//Output the modified class file
cc.writeFile();
}
Executing this test method will output the rewritten Integer class to ./java/lang/Integer.class
.
Then create the following main class.
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);
}
}
}
For run-time arguments
Add -Xbootclasspath / p: .
.
This will load the modified Integer class.
However, if you load this class
java.lang.InternalError
- klass: 'java/lang/InternalError'
#
# A fatal error has been detected by the Java Runtime Environment:
#
...
It cannot be executed probably because the value of Integer fluctuates when the JVM is executed.
So I will modify the Integer file further.
Make it an Integer class that works normally from the start of VM execution until the main class is executed.
@Test
public void testIntegerExport2() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("java.lang.Integer");
CtMethod m = cc.getDeclaredMethod("intValue");
//Have a flag inside
CtField isBroken = new CtField(CtClass.booleanType, "isBroken", cc);
isBroken.setModifiers(Modifier.PUBLIC);
cc.addField(isBroken, CtField.Initializer.constant(false));
//Add only if the flag is enabled
m.insertBefore("if(isBroken) value++;");
//Output the modified class file
cc.writeFile();
}
Add flag change processing to the main class.
public class A123 {
public static void main(String[] args) {
Integer a = Integer.valueOf(0);
try {
//Rewrite isBroken with reflection to avoid compilation errors
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();
}
}
}
If you try to change the value for an Integer isBroken If you rewrite it normally, the field does not exist, so I get a compile error. Therefore, by rewriting with reflection, a run-time error will occur if it does not exist. You can see the horror of reflection ...
Execution result
Also, if you add -Xbootclasspath / p: .
to the run-time argument and execute it,
true
I was able to successfully change (a == 1 && a == 2 && a == 3)
to true
in Java.
Recommended Posts