【问题标题】:Java String Mutability - java.lang.NoSuchFieldException: offsetJava 字符串可变性 - java.lang.NoSuchFieldException:偏移
【发布时间】:2013-07-05 12:56:18
【问题描述】:

我是 Java 新手,我看到了一个问答部分 here,其中包含两个删除可变性的示例。经测试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(); }
    } 

} 

我收到以下错误:

java.lang.NoSuchFieldException: offset

非常感谢您对以下内容的任何意见:

a) 为什么我会得到这个异常
b) 如何检查类中存在哪些字段(特别是 Java 字符串)

【问题讨论】:

  • offset中没有字段String...
  • 这种做事方式太恶心了-.-
  • @LaurentG:在 Java 6 中(或至少在 Oracle/Sun/OpenJDK 实现中)曾经有一个。当然,它从未被记录在案,因此取决于它显然是一个错误。

标签: java string immutability field nosuchfieldexception


【解决方案1】:

免责声明:这些技巧是有趣的学习课程和有趣的琐事。但它们绝对不是您想在任何生产代码中使用的东西。它导致疼痛。

就其本质而言,这样的黑客攻击总是取决于被黑客攻击的类的实现细节。

在您的情况下,您似乎正在使用没有 offset 字段的 String 实现,但使用了一些其他机制(或者可能只是不同的名称!)。

例如,我刚刚查看了 Oracle Java 7 String 类,它不再具有 offset 字段(在 Java 6 及更早版本中用于在子字符串之间共享 char[])!*

您可以使用Class.getDeclaredFields() 来检查此实现确实定义了哪些字段:

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

对于适用于 Java 7 的 hack 版本,您可以这样做:

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

当然,如果String 的内部结构再次发生变化,这也会中断。

* Here's an Email 谈到这一变化,似乎char[] 的共享只会在少数特殊情况下提高性能。

【讨论】:

  • 谢谢。我的初学者也获得了 +15 的声望,所以我终于可以对好的回应投赞成票了。
猜你喜欢
  • 2019-12-12
  • 1970-01-01
  • 2013-09-30
  • 2020-11-29
  • 2017-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多