2

以下代码尝试使用 Java 7private final char value[]为 String 类的字段设置一个值。

package test;

import java.lang.reflect.Field;

public final class Test 
{
    static
    {
        try
        {
            Field value = String.class.getDeclaredField("value");
            value.setAccessible(true);
            value.set("Hello World", value.get("1234567890"));
        }
        catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e)
        {
            System.out.println(e.toString());
        }
    }

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

它默默地显示1234567890在控制台上,毫无疑问。


当我尝试使用Java 6做同样的事情时,如下所示,

package test;

import java.lang.reflect.Field;

public final class Test
{
    static
    {
        try
        {
            Field value = String.class.getDeclaredField("value");
            value.setAccessible(true);
            value.set("Hello World", value.get("1234567890"));
        }
        catch (IllegalArgumentException e)
        {
            System.out.println(e.toString());
        }
        catch (IllegalAccessException e)
        {
            System.out.println(e.toString());
        }
        catch (NoSuchFieldException e)
        {
            System.out.println(e.toString());
        }
        catch (SecurityException e)
        {
            System.out.println(e.toString());
        }
    }
    public static void main(String[] args)
    {
        System.out.println("Hello World");
    }
}

它会导致引发以下异常。

线程“主”java.lang.ArrayIndexOutOfBoundsException 中的异常

value.get("1234567890")此语句value.set("Hello World", value.get("1234567890"));中的长度大于等于字符串时有效Hello World

例如,

如果以下语句(如前面的代码片段)

value.set("Hello World", value.get("1234567890"));

被类似下面的东西取代

value.set("Hello World", value.get("12345678901"));

那么,当方法的第二个参数的长度小于第一个参数时,为什么这不适用于Java 6(或者可能更低,我没有尝试过) ?set()

顺便说一句,我可以理解,根本不建议以这种方式处理具有反射的私有字段,而且是最糟糕的。

4

1 回答 1

5

那么当 set() 方法的第二个参数的长度小于第一个参数时,为什么这不适用于 Java 6(或者可能更低,我没有尝试过)?

在 Java 6 中,您正在设法将value字符数组设置为新引用 - 但您不会更改指定字符串引用的部分的其他字段。char[]

我不记得确切的字段名称,但它是这样的:

char[] value;
int offset;
int count;

因此,对于“覆盖”整个字符数组的字符串,将为offset0 和. 现在,如果您用更短的替换,但不更改,则超出数组的末尾......它超出了数组的范围。这样做是为了不需要复制字符数据之类的操作——它们只是创建一个引用现有数组的新对象,具有不同的偏移量/计数值。countvalue.lengthvalue char[]countoffset + countsubstring

从更新 5 开始的 Java 7 中,字符串没有这个偏移/计数概念;相反,每个字符串都有自己的字符数组,并且开头和结尾是隐式的。我怀疑这就是为什么它在 Java 7 中对你有用。

于 2013-01-27T20:50:34.823 回答