2

次のコードは、Java7を使用し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");
    }
}

そしてそれはコンソールに静かに表示さ1234567890れ、それについては疑問の余地はありません。


次のようにJava6を使用して同じことを行おうとすると、

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

では、メソッドの2番目のパラメーターの長さが最初のパラメーターよりも短いのに、なぜこれがJava 6で機能しないのでしょうか(または、もっと低くなる可能性がありますが、試しませんでした)。set()

ところで、このようにリフレクションを使ってプライベートフィールドを扱うことは、まったく推奨されておらず、最悪であることを理解できます。

4

1 に答える 1

5

では、set()メソッドの2番目のパラメーターの長さが最初のパラメーターよりも短いのに、なぜこれがJava 6で機能しないのでしょうか(または、もっと低くなる可能性がありますが、試しませんでした)。

Java 6では、文字配列を新しい参照に設定できますが、文字列が参照するセクションを指定する他のフィールドvalueは変更しません。char[]

正確なフィールド名を思い出せませんが、次のようになります。

char[] value;
int offset;
int count;

したがって、文字配列全体を「カバー」する文字列の場合、offsetは0になり、countはになりますvalue.lengthvalueここで、短い ものに置き換えてchar[]も変更しないcount場合offset + countは、配列の終わりを超えています...配列の境界の外側にあります。これはsubstring、文字データをコピーする必要がないなどの操作を行うために行われます。オフセット/カウント値が異なる既存の配列を参照する新しいオブジェクトを作成するだけです。

アップデート5以降のJava7では、文字列にはこのオフセット/カウントの概念がありません。代わりに、各文字列には独自の文字配列があり、開始と終了は暗黙的です。それがJava7で機能する理由だと思います。

于 2013-01-27T20:50:34.823 に答える