Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
什么是Java字符串实习?_Java_String_String Interning - Fatal编程技术网

什么是Java字符串实习?

什么是Java字符串实习?,java,string,string-interning,Java,String,String Interning,什么是Java中的字符串Interning,何时应该使用它,以及为什么? 基本上,对一系列字符串执行String.intern()将确保具有相同内容的所有字符串共享相同的内存。所以,如果你有一个“约翰”出现1000次的名字列表,通过实习,你可以确保只有一个“约翰”被实际分配了内存 这有助于减少程序的内存需求。但请注意,缓存是由JVM在永久内存池中维护的,与堆相比,永久内存池的大小通常是有限的,因此如果没有太多重复值,就不应该使用intern 更多关于使用intern()的内存限制的信息 一方面

什么是Java中的字符串Interning,何时应该使用它,以及为什么

基本上,对一系列字符串执行String.intern()将确保具有相同内容的所有字符串共享相同的内存。所以,如果你有一个“约翰”出现1000次的名字列表,通过实习,你可以确保只有一个“约翰”被实际分配了内存

这有助于减少程序的内存需求。但请注意,缓存是由JVM在永久内存池中维护的,与堆相比,永久内存池的大小通常是有限的,因此如果没有太多重复值,就不应该使用intern


更多关于使用intern()的内存限制的信息

一方面,确实可以通过 将它们内在化。问题是,内部化的字符串将转到 永久生成,是JVM中保留的一个区域 对于非用户对象,如类、方法和其他内部JVM 物体。这一地区的面积有限,通常要小得多 而不是堆。对字符串调用intern()会产生移动的效果 它从堆中出来,进入永久的一代,你就有风险了 PermGen空间不足

-- 发件人:


从JDK7(我的意思是在HotSpot中),有些东西已经改变了

在JDK 7中,内部字符串不再在Java堆的永久生成中分配,而是与应用程序创建的其他对象一起分配到Java堆的主要部分(称为年轻和老代)。此更改将导致更多数据驻留在主Java堆中,而永久生成中的数据将减少,因此可能需要调整堆大小。由于此更改,大多数应用程序在堆使用方面只会看到相对较小的差异,但是加载许多类或大量使用String.intern()方法的大型应用程序会看到更显著的差异

--从

更新:从Java7开始,插入的字符串存储在主堆中

有一些“吸引人的面试”问题,比如为什么你会得到平等!如果您执行下面的代码

String s1 = "testString";
String s2 = "testString";
if(s1 == s2) System.out.println("equals!");
如果要比较字符串,应使用
equals()
。上面的内容将打印为等号,因为编译器已经为您插入了
testString
。您可以使用intern方法自己插入字符串,如前面的答案所示……

JLS 定义并给出一个实际示例:

此外,字符串文字总是引用类字符串的同一实例。这是因为字符串文字(或者更一般地说,是常量表达式(§15.28)的值的字符串)被“插入”,以便使用string.intern方法共享唯一实例

示例3.10.5-1。字符串文本

由编译单元组成的程序(§7.3):

及编制组:

package other;
public class Other { public static String hello = "Hello"; }
生成输出:

true true true true false true
JVM 表示interning是通过专用的
常量\u String\u info
结构神奇高效地实现的(与大多数其他具有更通用表示的对象不同):

字符串文字是对类字符串实例的引用,它源自类或接口二进制表示中的常量字符串信息结构(§4.4.3)。常量字符串信息结构给出了组成字符串文字的Unicode代码点序列

Java编程语言要求相同的字符串文字(即包含相同代码点序列的文字)必须引用相同的类字符串实例(JLS§3.10.5)。此外,如果对任何字符串调用String.intern方法,则结果是对同一类实例的引用,如果该字符串显示为文本,则将返回该类实例。因此,以下表达式的值必须为true:

("a" + "b" + "c").intern() == "abc"
为了派生字符串文字,Java虚拟机检查常量字符串信息结构给出的代码点序列

  • 如果方法String.intern以前曾在包含Unicode码点序列的类String实例上被调用,该序列与常量字符串信息结构给出的序列相同,则字符串文字派生的结果是对该类String实例的引用

  • 否则,将创建一个新的类字符串实例,其中包含常量字符串信息结构给出的Unicode代码点序列;对该类实例的引用是字符串文字派生的结果。最后,调用新字符串实例的intern方法

字节码 让我们对一些OpenJDK 7字节码进行反编译,以查看实际操作

如果我们反编译:

public class StringPool {
    public static void main(String[] args) {
        String a = "abc";
        String b = "abc";
        String c = new String("abc");
        System.out.println(a);
        System.out.println(b);
        System.out.println(a == c);
    }
}
我们在恒定池上有:

#2 = String             #32   // abc
[...]
#32 = Utf8               abc
main

 0: ldc           #2          // String abc
 2: astore_1
 3: ldc           #2          // String abc
 5: astore_2
 6: new           #3          // class java/lang/String
 9: dup
10: ldc           #2          // String abc
12: invokespecial #4          // Method java/lang/String."<init>":(Ljava/lang/String;)V
15: astore_3
16: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
19: aload_1
20: invokevirtual #6          // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_2
27: invokevirtual #6          // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_1
34: aload_3
35: if_acmpne     42
38: iconst_1
39: goto          43
42: iconst_0
43: invokevirtual #7          // Method java/io/PrintStream.println:(Z)V
0:ldc#2//String abc
2:astore_1
3:ldc#2//字符串abc
5:astore_2
6:new#3//class java/lang/String
9:dup
10:ldc#2//字符串abc
12:invokespecial#4//方法java/lang/String.“:(Ljava/lang/String;)V
15:astore_3
16:getstatic#5//fieldjava/lang/System.out:Ljava/io/PrintStream;
19:aload_1
20:invokevirtual#6//方法java/io/PrintStream.println:(Ljava/lang/String;)V
23:getstatic#5//fieldjava/lang/System.out:Ljava/io/PrintStream;
26:aload_2
27:invokevirtual#6//方法java/io/PrintStream.println:(Ljava/lang/String;)V
30:getstatic#5//fieldjava/lang/System.out:Ljava/io/PrintStream;
33:aload_1
34:aload_3
35:if_acmpne 42
38:iconst_1
39:转到43
42:iconst_0
43:invokevirtual#7//方法java/io/PrintStream.println:(Z)V
请注意:

  • 0
    3
    :相同的
    ldc#2
     0: ldc           #2          // String abc
     2: astore_1
     3: ldc           #2          // String abc
     5: astore_2
     6: new           #3          // class java/lang/String
     9: dup
    10: ldc           #2          // String abc
    12: invokespecial #4          // Method java/lang/String."<init>":(Ljava/lang/String;)V
    15: astore_3
    16: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
    19: aload_1
    20: invokevirtual #6          // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    23: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
    26: aload_2
    27: invokevirtual #6          // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    30: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
    33: aload_1
    34: aload_3
    35: if_acmpne     42
    38: iconst_1
    39: goto          43
    42: iconst_0
    43: invokevirtual #7          // Method java/io/PrintStream.println:(Z)V
    
    object obj = "Int32";
    string str1 = "Int32";
    string str2 = typeof(int).Name;
    
    Console.WriteLine(obj == str1); // true
    Console.WriteLine(str1 == str2); // true    
    Console.WriteLine(obj == str2); // false !?
    
    String value1 = "70";
    String value2 = "70";
    String value3 = new Integer(70).toString();
    
    String str1 = "hello";
    String str2 = "hello";
    System.out.println(str1 == str2); //prints true
    
    String str3 = new String("hello");
    String str4 = new String("hello");
    
    System.out.println(str1 == str3); //prints false
    System.out.println(str3 == str4); //prints false 
    
    String str1 = "hello";
    String str2 = new String("hello");
    String str3 = str2.intern(); //get an interned string obj
    
    System.out.println(str1 == str2); //prints false
    System.out.println(str1 == str3); //prints true
    
    Java interning() method basically makes sure that if String object is present in SCP, If yes then it returns that object and if not then creates that objects in SCP and return its references
    
    for eg: String s1=new String("abc");
            String s2="abc";
            String s3="abc";
    
    s1==s2// false, because 1 object of s1 is stored in heap and other in scp(but this objects doesn't have explicit reference) and s2 in scp
    s2==s3// true
    
    now if we do intern on s1
    s1=s1.intern() 
    
    //JVM checks if there is any string in the pool with value “abc” is present? Since there is a string object in the pool with value “abc”, its reference is returned.
    Notice that we are calling s1 = s1.intern(), so the s1 is now referring to the string pool object having value “abc”.
    At this point, all the three string objects are referring to the same object in the string pool. Hence s1==s2 is returning true now.
    
    class InternDemo
    {
    public static void main(String[] args)
    {
    String s1=new String("smith");
    String s2=s1.intern();
    String s3="smith";
    System.out.println(s2==s3);//true
    }
    }