Java String Mutability - java.lang.NoSuchFieldException: offset

杀马特。学长 韩版系。学妹 提交于 2019-12-22 10:17:37

问题


I'm new to Java and I saw a Q&A section here with two examples where mutability is removed. Upon testing MutableString.java:

import java.lang.reflect.Field; 

public class MutableString {

    public static void main(String[] args) { 
        String s = "Immutable"; 
        String t = "Notreally"; 

        mutate(s, t);
        StdOut.println(t); 

        // strings are interned so this doesn't even print "Immutable" (!)
        StdOut.println("Immutable");
    } 

    // change the first min(|s|, |t|) characters of s to t
    public static void mutate(String s, String t) {
        try {
            Field val = String.class.getDeclaredField("value"); 
            Field off = String.class.getDeclaredField("offset"); 
            val.setAccessible(true); 
            off.setAccessible(true); 
            int offset   = off.getInt(s); 
            char[] value = (char[]) val.get(s); 
            for (int i = 0; i < Math.min(s.length(), t.length()); i++)
                value[offset + i] = t.charAt(i); 
        } 
        catch (Exception e) { e.printStackTrace(); }
    } 

} 

I received the following error:

java.lang.NoSuchFieldException: offset

Any input on the following would be greatly appreciated:

a) why do I get this exception
b) how do I check which fields exist in a class (Java strings specifically)


回答1:


Disclaimer: these kinds of hacks are interesting lessons in learning and fun trivia. But they are definitely not something that you want to use in any production code. It will lead to pain.

By their very nature, such a hack always depends on implementation details of the classes that are hacked.

In your case you seem to be using a String implementation that doesn't have an offset field, but uses some other mechanism (or maybe just a different name!).

For example, I've just reviewed the Oracle Java 7 String class and it no longer has the offset field (which was used in Java 6 and earlier to share the char[] among substrings)!*

You can use Class.getDeclaredFields() to check which fields this implementation does define:

for (Field f : String.class.getDeclaredFields()) {
  System.out.println(f);
}

For a version of that hack that works with Java 7, you could do this:

public static void mutate(String s, String t) {
    try {
        Field val = String.class.getDeclaredField("value"); 
        val.setAccessible(true); 
        char[] value = (char[]) val.get(s); 
        for (int i = 0; i < Math.min(s.length(), t.length()); i++)
            value[i] = t.charAt(i); 
    } 
    catch (Exception e) { e.printStackTrace(); }
} 

Of course, this too will break if the internals of String change again.

* Here's an Email that talks about that change, it seems that the sharing of the char[] only lead to improved performance in a few, special cases.



来源:https://stackoverflow.com/questions/17489467/java-string-mutability-java-lang-nosuchfieldexception-offset

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!