Tin*_*iny 2 java string reflection java-6 java-7
以下代码尝试使用Java 7将值设置为private 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");
}
}
Run Code Online (Sandbox Code Playgroud)
它默默地显示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");
}
}
Run Code Online (Sandbox Code Playgroud)
它会导致抛出以下异常.
线程"main"java.lang.ArrayIndexOutOfBoundsException中的异常
当value.get("1234567890")此语句中的长度value.set("Hello World", value.get("1234567890"));大于或等于String 时,它可以工作Hello World
例如,
如果以下语句(如前面的代码片段中所示)
value.set("Hello World", value.get("1234567890"));
Run Code Online (Sandbox Code Playgroud)
由以下内容替换
value.set("Hello World", value.get("12345678901"));
Run Code Online (Sandbox Code Playgroud)
那么,当方法的第二个参数的长度小于第一个参数时,为什么这不适用于Java 6(或者可能更低,我没试过)set()?
顺便说一句,我可以理解,不建议以这种方式处理带有反射的私有字段,这是最糟糕的.
那么当set()方法的第二个参数的长度小于第一个参数时,为什么这不适用于Java 6(或者可能更低,我没试过)?
在Java 6中,您正在设置将value字符数组设置为新引用 - 但您不会更改指定字符串引用的部分的其他字段char[].
我不记得确切的字段名称,但它是这样的:
char[] value;
int offset;
int count;
Run Code Online (Sandbox Code Playgroud)
因此,对于"覆盖"整个字符数组的字符串,offset将为0并且count将是value.length.现在如果value用更短的 替换char[],但不改变count,则offset + count超出数组的末尾......它超出了数组的范围.这样做是为了使操作像substring不需要复制字符数据 - 它们只是创建一个新对象,该对象引用现有数组,具有不同的偏移/计数值.
在Java 7中,从更新5开始,字符串没有此偏移/计数概念; 相反,每个字符串都有自己的字符数组,开头和结尾都是隐式的.我怀疑这就是为什么它在Java 7中适合你的原因.