L'histoire originale est cet article sur StackOverflow JavaScript. https://stackoverflow.com/questions/48270127/can-a-1-a-2-a-3-ever-evaluate-to-true
Comme le révèle une graine, ** Si vous remplacez la conversion de type implicite dans JavaScript et y mettez le traitement, vous pouvez l'exécuter au moment de la comparaison! ** ** C'est pourquoi vous pouvez utiliser Java si vous le remplacez par la classe héritée!
Au cas où, vérifions la conversion de type implicite de Java.
@Test
public void test_integer() {
Integer a = Integer.valueOf(1);
if(a == 1){
System.out.println("true");
}
}
Ceci est comparé en appelant ʻintValue () de ʻInteger
lors de la comparaison avec int.
En Java, cela s'appelle unboxing.
Échec car la classe Integer est finale et ne peut pas être remplacée Ou plutôt, si vous remplacez la valeur intValue de Integer, vous mourrez de différentes manières.
Alors, créons une classe numérique en héritant de la classe Number, qui est la classe abstraite parente d'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);
}
}
Depuis que j'ai implémenté intValue () et également implémenté l'interface de 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:Les types StrangeObject et int ne peuvent pas être comparés
Inutile de vérifier le type avant comparaison ...
@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");
}
}
Cela fonctionne, mais que dois-je faire pour supprimer (exécuter implicitement) intValue ()?
À partir de maintenant, l'obscurité sera assez profonde, alors vérifions-le.
Puisqu'il a été souligné dans le commentaire qu'il ne sera pas déballé à moins qu'il ne soit dans certaines classes système Réécrivez la classe système.
Utilisez Javassist pour réécrire le fichier de classe Integer.
Dans le cas d'une classe système, elle ne peut pas être réécrite à l'exécution, donc Il est craché une fois en tant que fichier statique et le fichier réécrit est lu au moment de l'exécution.
@Test
public void testIntegerExport() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("java.lang.Integer");
CtMethod method = cc.getDeclaredMethod("intValue");
//value dans intValue++Ajoutée
method.insertBefore("value++;");
//Sortie du fichier de classe modifié
cc.writeFile();
}
L'exécution de cette méthode de test affichera la classe Integer réécrite dans . / Java / lang / Integer.class
.
Créez ensuite la classe principale suivante.
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);
}
}
}
Pour les arguments d'exécution
Ajoutez -Xbootclasspath / p: .
.
Cela chargera la classe Integer modifiée.
Cependant, si vous chargez cette classe
java.lang.InternalError
- klass: 'java/lang/InternalError'
#
# A fatal error has been detected by the Java Runtime Environment:
#
...
Il ne peut pas être exécuté probablement parce que la valeur de Integer fluctue lorsque la JVM est exécutée.
Je vais donc modifier davantage le fichier Integer.
Faites-en une classe Integer qui fonctionne normalement du début de l'exécution de la VM jusqu'à ce que la classe principale soit exécutée.
@Test
public void testIntegerExport2() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("java.lang.Integer");
CtMethod m = cc.getDeclaredMethod("intValue");
//Avoir un drapeau à l'intérieur
CtField isBroken = new CtField(CtClass.booleanType, "isBroken", cc);
isBroken.setModifiers(Modifier.PUBLIC);
cc.addField(isBroken, CtField.Initializer.constant(false));
//Ajouter uniquement si l'indicateur est activé
m.insertBefore("if(isBroken) value++;");
//Sortie du fichier de classe modifié
cc.writeFile();
}
Ajoutez le traitement des changements d'indicateur à la classe principale.
public class A123 {
public static void main(String[] args) {
Integer a = Integer.valueOf(0);
try {
//Réécrire isBroken avec réflexion pour éviter les erreurs de compilation
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();
}
}
}
Si vous essayez de modifier la valeur de isBroken of Integer Si vous le réécrivez normalement, le champ n'existe pas, donc J'obtiens une erreur de compilation. Par conséquent, en réécrivant avec réflexion, une erreur d'exécution se produira si elle n'existe pas. Vous pouvez voir l'horreur de la réflexion ...
Résultat d'exécution
De plus, si vous ajoutez -Xbootclasspath / p: .
à l'argument d'exécution et que vous l'exécutez,
true
J'ai réussi à changer (a == 1 && a == 2 && a == 3)
en true
en Java.
Recommended Posts