【问题标题】:String POOL in javajava中的字符串池
【发布时间】:2012-01-09 12:04:04
【问题描述】:

Java 有字符串池,因此字符串类的对象是不可变的。

但我的问题是 -

制作String POOL需要什么?

为什么字符串类没有像其他类一样保存自己的值?

是 JVM 内部需要一些字符串还是性能优势。如果是怎么办?

【问题讨论】:

标签: java string pool


【解决方案1】:

池是可能的,因为字符串是不可变的。但是字符串的不变性并没有仅仅因为这个池而被决定。不变性还有许多其他好处。顺便说一句,Double 也是不可变的,并且没有 Doubles 池。

对字符串池的需求是减少保存程序使用的所有字符串文字(和内部字符串)所需的内存,因为这些文字很有可能在程序的许多地方被多次使用.您只需对同一个字符串进行数千个引用,而不是拥有数千个相同字符串字面量的副本,从而减少了内存使用量。

请注意,String 类与其他类没有什么不同:它拥有自己的 char 数组。但是,当调用 substring 时,它也可以与其他 String 实例共享它。

【讨论】:

  • Double 也是不可变的,并且没有 Doubles 池 不错的选择.. :) 谢谢
  • “程序生成的字符串文字”是什么意思?你是说即使应用程序不能处理文本并且没有显式创建许多 String 对象,JVM 也会在内部生成许多类似的字符串?
  • 不,我的意思恰恰相反:如果 200 个类在其代码中使用字符串文字 "",则只会创建一个实例,将其存储在字符串池中,并由所有课程。
【解决方案2】:

String POOL 需要什么?

创建时,String 对象存储在堆中,而在构造函数中发送的 String 字面量存储在 SP 中。这就是为什么使用 String 对象不是一个好习惯的原因。因为它创建了两个对象。

String str = new String("stackoverflow");

上面的 str 与引用 str 一起保存在堆中,来自构造函数的字符串字面量 -“stackoverflow” - 存储在字符串池中。这对性能不利。两个对象被装箱。

流程:创建字符串字面量 -> JVM 在字符串池中查找值是否存在相同的值(没有要返回的对象) -> 找不到值 -> 字符串字面量是创建为新对象(内部使用 new 关键字)-> 但现在不发送到堆,而是在字符串池中发送。

区别在于使用 new 关键字创建对象的位置。如果它是由程序员创建的,它将直接在堆中发送对象,没有延迟。如果它是在内部创建的,它会被发送到 String Poll。这是通过方法intern() 完成的。在声明 String 文字时,intern() 会在内部调用。此方法在 SP 中搜索与返回现有 String 对象的引用或/和将对象发送到 SP 相同的值。

当使用 new 创建 String obj 时,不会调用 intern() 并且对象存储在堆中。但是您可以在 String obj 上调用 intern(): String str = new String().intern();现在 str 对象将存储在 SP 中。 例如:

String s1 = new String("hello").intern();
String s2 = "hello";
System.out.println(s1 == s2); // true , because now s1 is in SP

【讨论】:

    【解决方案3】:

    当我们编译器看到必须创建一个新的字符串字面量时,它首先检查池中是否有相同的字符串,如果没有创建新的字符串字面量,则引用现有的字符串。

    【讨论】:

    • 编译器实际上与此无关。文字放在类文件中,并在加载类时由池解析。
    • 那么你的意思是如果找到匹配项,池中的字符串就不会被引用?
    【解决方案4】:

    将字符串设为不可变的好处在于安全功能。阅读下文

    为什么 String 在 Java 中是不可变的?

    虽然,性能也是一个原因(假设您已经知道为确保多次使用同一个 String 对象而无需多次创建/重新声明它而维护的内部字符串池),但是String 在 Java 中不可变的主要原因是“安全性”。惊讶吗?让我们了解原因。

    假设您需要打开一个要求用户进行身份验证的安全文件。假设有两个用户名为“user1”和“user2”,他们分别有自己的密码文件“password1”和“password2”。显然 'user2' 不应该访问 'password1' 文件。

    众所周知,Java 中的文件名是使用字符串指定的。即使您创建了一个“文件”对象,您也只能将文件名作为字符串传递,并且该字符串作为其成员之一在文件对象中维护。

    如果 String 是可变的,“user1”可能已经使用他的凭据登录,然后在 JVM 实际放置用于打开文件的本机操作系统系统调用。这将允许“user1”打开 user2 的密码文件。可以理解的是,这会导致 Java 中的一个重大安全漏洞。我知道这里有很多“可能”,但您肯定会同意,它会为开发人员有意或无意地破坏许多资源的安全性打开一扇门。

    由于字符串是不可变的,JVM 可以确保相应文件对象的文件名实例成员将继续指向相同的未更改的“文件名”字符串对象。作为 File 类中的“final”的 'filename' 实例成员无论如何都不能被修改为指向任何其他 String 对象,该对象指定任何其他文件,而不是预期的文件(即,用于创建 File 对象的文件)。

    【讨论】:

    • 这并不是真正的安全原因。如果字符串在 Java 中是可变的,则 File 类只需将带有文件名的字符串复制到一个新的 String 对象中。它唯一的性能特征是不需要这种复制(以及程序员不会忘记所需复制的便利特征)。
    猜你喜欢
    • 2010-12-26
    • 2013-06-08
    • 1970-01-01
    • 2014-09-14
    • 1970-01-01
    • 2015-01-23
    • 1970-01-01
    • 1970-01-01
    • 2011-07-24
    相关资源
    最近更新 更多