Javadoc关于String.intern()没有提供太多细节.(简而言之:它返回字符串的规范表示,允许使用内部字符串进行比较==)
String.equals()?String.intern()吗?Dan*_*ner 193
这(几乎)与字符串比较无关.如果您的应用程序中有许多具有相同内容的字符串,则字符串实习用于保存内存.通过使用String.intern()应用程序,从长远来看只有一个实例,副作用是你可以执行快速引用相等比较而不是普通的字符串比较(但这通常是不可取的,因为它只是因为忘记实习生而很容易打破单个实例).
dfa*_*dfa 125
我什么时候会使用这个函数来支持String.equals()
当你需要速度,因为你可以通过引用比较字符串(==快于等于)
是否有Javadoc中没有提到的副作用?
主要的缺点是你必须记住确保你实际上做了你要比较的所有字符串intern().很容易忘记intern()所有字符串,然后你可以得到令人困惑的错误结果.此外,为了每个人的利益,请务必非常清楚地记录您依赖于内部化的字符串.
如果您决定内化字符串,第二个缺点是intern()方法相对昂贵.它必须管理唯一字符串池,以便它做相当多的工作(即使字符串已经内化).所以,在你的代码设计中要小心,这样你就可以在输入中输入所有适当的字符串,这样你就不必再担心它了.
(来自JGuru)
第三个缺点(仅限Java 7或更低版本):实习字符串存在于PermGen空间中,通常非常小; 您可能遇到具有大量可用堆空间的OutOfMemoryError.
(来自Michael Borgwardt)
Gil*_*hum 36
String.intern()绝对是现代JVM中的垃圾收集.
由于GC活动,以下NEVER内存不足:
// java -cp . -Xmx128m UserOfIntern
public class UserOfIntern {
public static void main(String[] args) {
Random random = new Random();
System.out.println(random.nextLong());
while (true) {
String s = String.valueOf(random.nextLong());
s = s.intern();
}
}
}
Run Code Online (Sandbox Code Playgroud)
在非GCed String.intern()的神话中看到更多(来自我).
小智 16
我最近在Java 6,7和8中编写了一篇关于String.intern()实现的文章:Java 6,7和8中的 String.intern - 字符串池.
我希望它应该包含有关Java中字符串池的当前情况的足够信息.
简而言之:
String.intern()在Java 6中,因为它进入了PermGenString.intern()Java 7和Java 8:它使用的内存比滚动自己的对象池少4-5倍-XX:StringTableSize(默认值可能太小;设置一个素数)ale*_*oot 13
使用==比较字符串比使用equals()快得多
5时间更快,但由于字符串比较通常仅占应用程序总执行时间的一小部分,因此整体增益远小于此,并且最终收益将被稀释到几个百分点.
String.intern()将字符串拉离Heap并将其放入PermGen
内部化的字符串放在不同的存储区域中:永久生成,它是为非用户对象保留的JVM区域,如类,方法和其他内部JVM对象.这个区域的大小是有限的,并且比堆更珍贵.由于此区域比Heap小,因此使用所有空间并获得OutOfMemoryException的可能性更大.
String.intern()字符串是垃圾回收
在新版本的JVM中,内部化字符串在没有被任何对象引用时被垃圾收集.
记住上面的3点,你可以推断出String intern()只有在很少的情况下你做了很多字符串比较才有用,但如果你不确切知道你是什么,最好不要使用内部字符串是做 ...
我什么时候会使用这个函数来支持String.equals()
鉴于他们做不同的事情,可能永远不会.
出于性能原因的内部字符串,以便您可以比较它们以获得引用相等性,只有在持有对字符串的引用一段时间才会有好处 - 来自用户输入的字符串或IO将不会被实现.
这意味着在您的应用程序中,您从外部源接收输入并将其处理为具有语义值的对象 - 标识符说 - 但该对象具有与原始数据无法区分的类型,并且对于程序员应该如何应该具有不同的规则用它.
创建一个内部UserId类型(很容易创建一个线程安全的通用实习机制)并且像开放枚举一样,几乎总是更好,而不是java.lang.String如果恰好是用户ID那么用引用语义重载类型.
这样,您就不会混淆特定字符串是否已被实现,并且您可以在开放枚举中封装所需的任何其他行为.
\n\n\n是否存在 Javadoc 中未提及的副作用,即 JIT 编译器或多或少的优化?
\n
我不知道 JIT 级别,但对字符串池有直接的字节码支持,它是通过专用CONSTANT_String_info结构神奇而高效地实现的(与具有更通用表示的大多数其他对象不同)。
\n\n\n字符串文字是对 String 类实例的引用,派生自类或接口的二进制表示形式中的 CONSTANT_String_info 结构 (\xc2\xa74.4.3)。CONSTANT_String_info 结构给出了构成字符串文字的 Unicode 代码点序列。
\n\nJava 编程语言要求相同的字符串文字(即包含相同代码点序列的文字)必须引用 String 类的相同实例 (JLS \xc2\xa73.10.5)。此外,如果对任何字符串调用 String.intern 方法,则结果是对同一类实例的引用,如果该字符串作为文字出现,则将返回该类实例。因此,以下表达式的值必须为 true:
\n
("a" + "b" + "c").intern() == "abc"\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n\n为了派生字符串文字,Java 虚拟机检查 CONSTANT_String_info 结构给出的代码点序列。
\n\n\n
\n- \n
如果先前已在包含与 CONSTANT_String_info 结构给出的序列相同的 Unicode 代码点序列的 String 类实例上调用了 String.intern 方法,则字符串文字派生的结果是对 String 类的同一实例的引用。
- \n
否则,将创建 String 类的新实例,其中包含 CONSTANT_String_info 结构给出的 Unicode 代码点序列;对该类实例的引用是字符串文字派生的结果。最后,调用新String实例的intern方法。
查看 OpenJDK 7 上的字节码实现也很有启发性。
\n\n如果我们反编译:
\n\npublic class StringPool {\n public static void main(String[] args) {\n String a = "abc";\n String b = "abc";\n String c = new String("abc");\n System.out.println(a);\n System.out.println(b);\n System.out.println(a == c);\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n我们在常量池上有:
\n\n#2 = String #32 // abc\n[...]\n#32 = Utf8 abc\nRun Code Online (Sandbox Code Playgroud)\n\n和main:
0: ldc #2 // String abc\n 2: astore_1\n 3: ldc #2 // String abc\n 5: astore_2\n 6: new #3 // class java/lang/String\n 9: dup\n10: ldc #2 // String abc\n12: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V\n15: astore_3\n16: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;\n19: aload_1\n20: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V\n23: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;\n26: aload_2\n27: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V\n30: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;\n33: aload_1\n34: aload_3\n35: if_acmpne 42\n38: iconst_1\n39: goto 43\n42: iconst_0\n43: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V\nRun Code Online (Sandbox Code Playgroud)\n\n注意如何:
\n\n0and 3:ldc #2加载相同的常量(文字)12:创建一个新的字符串实例(作为#2参数)35:a并c作为常规对象进行比较if_acmpne常量字符串的表示在字节码上非常神奇:
\n\nnew String)上面的 JVMS 引用似乎是说,每当 Utf8 指向相同时,就会加载相同的实例ldc。
我对字段做了类似的测试,并且:
\n\nstatic final String s = "abc"通过ConstantValue 属性指向常量表ldc好处:将其与整数池进行比较,后者没有直接的字节码支持(即没有CONSTANT_String_info类似物)。
| 归档时间: |
|
| 查看次数: |
60954 次 |
| 最近记录: |