一个简单的Java代码,运行良好但功能有点难以理解

时间:2011-11-10 20:46:08

标签: java

以下简单的Java程序似乎通过语句System.out.println("Hello World");显示字符串 Hello World ,但事实并非如此。它只是用另一个字符串替换它,在这种情况下, Good Day !! 并将其显示在控制台上。根本不显示字符串 Hello World 。让我们看看Java中的以下简单代码片段。

package goodday;

import java.lang.reflect.Field;

final public class Main 
{
    public static void main(String[] args) 
    {        
        System.out.println("Hello World");
    }

    static 
    {
        try 
        {
            Field value = String.class.getDeclaredField("value");
            value.setAccessible(true);
            value.set("Hello World", value.get("Good Day !!"));
        } 
        catch (Exception e)
        {
            throw new AssertionError(e);
        }
    }
}

这里只有一个关于此代码的问题。它完全符合预期,但我不能减少字符串的长度美好的一天!! 。如果尝试这样做,则会导致java.lang.ArrayIndexOutOfBoudsException。如果长度增加,程序运行良好但显示字符串中的其余字符被截断意味着两个字符串的长度应该有些相同。为什么?这是我无法理解的事情。

1 个答案:

答案 0 :(得分:7)

value字段是char[],它在内部存储字符串用作其后备存储的字符数组。其他字段表示字符数组的初始偏移量和字符串的长度。 (因此,为了获取子字符串,它只是创建一个新的String对象,该对象引用相同的char[]但具有不同的起始偏移量和长度。)

如果你也修改这些字段,你可以用字符串做任何你喜欢的事情。样品:

import java.lang.reflect.Field;

public class Test
{
    // Obviously in real code you wouldn't use Exception like this...
    // Although hacking string values with reflection is worse, of course.
    public static void main(String[] args) throws Exception
    {        
        System.out.println("Hello World");
        replaceHelloWorld("Goodbye!");
        System.out.println("Hello World");
        replaceHelloWorld("Hello again!");
        System.out.println("Hello World");
    }

    static void replaceHelloWorld(String text) throws Exception
    {
        // Note: would probably want to do hash as well...
        copyField(text, "Hello World", "value");
        copyField(text, "Hello World", "offset");
        copyField(text, "Hello World", "count");
    }

    static void copyField(String source, String target, String name)
        throws Exception
    {
        Field field = String.class.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target, field.get(source));
    }
}