[JAVA]反射修改 String 常量

声明:此题目由 jeschou 原创

一个看似不可能的题目

public class Test {
    public static void main(String[] args) throws Exception {
        // add your magic code here
        System.out.println("AAAA".equals("BBBB"));
    }
}

要求: 在 注释处 添加任意代码,是最终打印结果是 true

考察点是 使得 "AAAA".equals("BBBB") == true


分析

String 是 java 语言中极其重要的一个类, 它被声明为 final 。
我们通常认为 String 是常量, 不可修改。
但是,凡是总有例外。

如果我已经有一个 String 对象, 还是可以通过反射修改的。

public class Test {
    public static void main(String[] args) throws Exception {
        String str = "abcd";
        java.lang.reflect.Field f = String.class.getDeclaredField("value");
        f.setAccessible(true);
        char[] charArray = (char[])f.get(str);
        charArray[0] = 'A';
        System.out.println(str);
    }
}

打印结果是 Abcd (a 被改成了 A)

至少有一点可以说明, String 并非不可修改!


回过头来再看下题目,棘手的点在于并没有一个对象引用 "AAAA" 和 "BBBB",它们都是常量。

常量怎么修改?

也是有办法的,虽然不能直接修改,但可以间接修改。
利用常量池!

public class Test {
    public static void main(String[] args) throws Exception {
        String str = "AAAA";
        java.lang.reflect.Field f = String.class.getDeclaredField("value");
        f.setAccessible(true);
        char[] charArray = (char[])f.get(str);
        java.util.Arrays.fill(charArray, 'B');
        System.out.println("AAAA".equals("BBBB"));
    }
}

先主动定义一个字符串 AAAA, 再出现 AAAA 时, 会直接使用先前定义的常量,它们是同一个对象。

你可能感兴趣的:([JAVA]反射修改 String 常量)