当前位置: 首页 > 面试题库 >

字符串文字,内部和反射

石超
2023-03-14
问题内容

我正在尝试找到这个问题的第三种解决方案。

我不明白为什么这个不打印false

public class MyClass {

    public MyClass() {
        try {
            Field f = String.class.getDeclaredField("value");
            f.setAccessible(true);
            f.set("true", f.get("false"));
        } catch (Exception e) {
        }
    }

    public static void main(String[] args) {
        MyClass m = new MyClass();
        System.out.println(m.equals(m));
    }
}

当然,由于使用字符串实习,"true"被修改的实例printPrintStream?方法中使用的实例完全相同。

public void print(boolean b) {
    write(b ? "true" : "false");
}

我想念什么?

编辑

@yshavit有趣的一点是,如果您添加该行

System.out.println(true);

在之前try,输出为

true
false

问题答案:

可以说这是HotSpot JVM错误。

问题在于字符串字面量的内部机制

  • java.lang.String 在常量池解析期间,将懒惰地创建字符串文字的实例。
  • 最初,字符串常量在常量池中由CONSTANT_String_info指向的结构表示CONSTANT_Utf8_info
  • 每个类都有自己的常量池。也就是说,MyClass而且PrintStream有自己的一双CONSTANT_String_info/ CONSTANT_Utf8_infoCPOOL条目文字 “真”
  • CONSTANT_String_info首次被访问时,JVM启动解决进程。字符串实习是此过程的一部分。
  • 为了找到被禁派文字的匹配项,JVM将的内容CONSTANT_Utf8_info与中的字符串实例的内容进行比较StringTable
  • ^^^这就是问题所在。将来自cpool的原始UTF数据与Java char[]数组内容进行比较,该内容可以由用户通过Reflection欺骗。

那么,您的测试中发生了什么?

  1. f.set("true", f.get("false"))启动字面的决议 “真”MyClass
  2. JVM在StringTable匹配序列 “ true”时 未发现任何实例,并创建了一个新实例,并将java.lang.String其存储在中StringTable
  3. value该字符串来自的字符串StringTable通过反射替换。
  4. System.out.println(true)在类中启动字面量 “ true” 的解析PrintStream
  5. JVM将UTF序列 “ true” 与来自的字符串进行比较StringTable,但未找到匹配项,因为该字符串已具有 “ false” 值。创建另一个 ‘true’ 字符串并将其放置在中StringTable

为什么我认为这是一个错误?

JLS§3.10.5和JVMS§5.1需要包含相同的字符序列串文字必须指向的同一个实例java.lang.String

但是,在下面的代码中,具有 相同 字符序列的两个字符串文字的解析导致 不同的 实例。

public class Test {

    static class Inner {
        static String trueLiteral = "true";
    }

    public static void main(String[] args) throws Exception {
        Field f = String.class.getDeclaredField("value");
        f.setAccessible(true);
        f.set("true", f.get("false"));

        if ("true" == Inner.trueLiteral) {
            System.out.println("OK");
        } else {
            System.out.println("BUG!");
        }
    }
}

JVM的一个可能解决方法是将指向原始UTF序列的指针StringTablejava.lang.String对象一起存储,以便内部处理过程不会将cpool数据(用户无法访问)与value数组(可通过Reflection访问)进行比较。



 类似资料:
  • 我有一个结果集,其中列出了他们所在的证券交易所和国家。尽管如此,在我的数据库中,并不是每个Cxchange都有一个country\u id,因此在创建Exchange对象时,其中许多对象都有country\u id和country\u title空值。由于内存优化,我计划对所有重复字符串(国家、货币等)进行内部存储,但注意到,我得到了一个NullPointerException,这是逻辑上的。是否

  • 问题内容: 这是以前有关Java中的String初始化的一些问题的后续问题。 在用Java进行了一些小测试之后,我面临以下问题: 为什么我可以执行此语句 当str2一个String对象初始化为,但我不能调用方法toString()上str2?那么Java如何将空字符串对象和字符串文字串联起来? 顺便说一句,我还尝试将一个初始化为null和字符串文字的Integer连接起来,”a_literal_s

  • 字符串是一系列的字符,比如说 "hello, world"或者 "albatross"。Swift 的字符串用String类型来表示。String的内容可以通过各种方法来访问到,包括作为Character值的集合。 Swift 的 String  和 Character  类型提供了一种快速的符合 Unicode 的方式操作你的代码。字符串的创建和修改语法非常轻量易读,使用与 C 类似的字符串字面

  • 本页包含内容: 字符串字面量 初始化空字符串 字符串可变性 字符串是值类型 使用字符 计算字符数量 连接字符串和字符 字符串插值 比较字符串 字符串大小写 Unicode String是例如"hello, world","海贼王"这样的有序的Character(字符)类型的值的集合,通过String类型来表示。 Swift 的String和Character类型提供了一个快速的,兼容 Unicod

  • NSString是最常用的类,用于存储字符串和文本。 如果您想了解更多有关NSString的信息,请参阅Objective-C字符串中的NSString 。 如前所述,NSCharacterSet表示NSString和NSScanner类使用的各种字符分组。 NSCharacterSet (NSCharacterSet) 以下是NSCharacterSet中可用的方法集,它们表示各种字符集。 al

  • 当我有一个字符串需要将一个字符连接到它的结尾时,我应该更喜欢超过是否有任何性能原因? 我知道数组字符串连接和字符串生成器,我并不是在询问一般情况下如何连接字符串的建议。 我也知道有些人会有冲动向我解释过早的优化,而且一般来说我不应该为这些小事情费心,请不要... 我之所以问这个问题,是因为从编码风格的偏好来看,我更倾向于使用后一个,但我觉得第一个应该表现得稍微好一点,因为知道所附加的只是一个字符,