简体   繁体   English

如果尝试使用反射将值设置为String类的value []字段,则Java 6和Java 7会产生不同的结果

[英]Java 6 and Java 7 yield different results, if an attempt is made to set a value to the value[] field of the String class using reflection

The following code attempts to set a value to the private final char value[] field of the String class using Java 7 . 以下代码尝试使用Java 7将值设置为String类的private final char value[]字段。

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");
    }
}

and it silently displays 1234567890 on the console and there is no question about it. 并在控制台上静默显示1234567890 ,对此毫无疑问。


When I try to do the same thing using Java 6 like the following, 当我尝试使用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");
    }
}

it causes the following exception to be thrown. 它导致引发以下异常。

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException 线程“主”中的异常java.lang.ArrayIndexOutOfBoundsException

It works when the length of value.get("1234567890") in this statement value.set("Hello World", value.get("1234567890")); 当此语句中value.get("1234567890")的长度value.set("Hello World", value.get("1234567890"));起作用时,此方法value.set("Hello World", value.get("1234567890")); is grater than or equal to the String Hello World 大于或等于String Hello World

For example, 例如,

If the following statement (as in the preceding code snippet) 如果以下语句(如前面的代码片段所示)

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

is replaced by something like the following 替换为以下内容

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

So why doesn't this work with Java 6 (or might be lower, I didn't try) when the length of the second parameter of the set() method is less than the first one? 那么,当set()方法的第二个参数的长度小于第一个参数的长度时,为什么这在Java 6中不起作用(或者可能更低,我没有尝试)?

BTW, I can understand that dealing with private fields with reflection in this way is not recommended at all and is worst. 顺便说一句,我可以理解,根本不建议以这种方式处理具有反射的私有字段,这是最糟糕的。

So why doesn't this work with Java 6 (or might be lower, I didn't try) when the length of the second parameter of the set() method is less than the first one? 那么,当set()方法的第二个参数的长度小于第一个参数的长度时,为什么这在Java 6中不起作用(或者可能更低,我没有尝试)?

In Java 6, you're managing to set the value character array to the new reference - but you're not changing the other fields which specify the section of the char[] which the string refers to. 在Java 6中,您正在设法将value字符数组设置为新的引用-但是您没有更改其他指定字符串所引用的char[]部分的其他字段。

I can't remember the exact field names, but it's something like this: 我不记得确切的字段名称,但这是这样的:

char[] value;
int offset;
int count;

So for a string which "covers" the entire character array, offset would be 0 and count would be value.length . 因此,对于“覆盖”整个字符数组的字符串, offset将为0, count将为value.length Now if you replace value with a shorter char[] , but don't change count , then offset + count is beyond the end of the array... it's outside the bounds of the array. 现在,如果您用较短的 char[]替换value ,但不更改count ,则offset + count超出了数组的末尾……它超出了数组的范围。 This is done so that operations like substring don't need to copy the character data - they just create a new object which refers to the existing array, with different offset / count values. 这样做是为了使诸如substring操作不需要复制字符数据,它们只是创建一个新对象,该对象引用具有不同偏移量/计数值的现有数组。

In Java 7 from update 5 onwards, strings don't have this offset/count concept; 从更新版本5开始的Java 7中,字符串没有此偏移量/计数概念。 instead, each string has its own character array and the start and end are implicit. 相反,每个字符串都有其自己的字符数组,并且开始和结束是隐式的。 I suspect that's why it works for you in Java 7. 我怀疑这就是为什么它在Java 7中对您有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM