關(guān)于java String中intern的深入講解
序
本文主要研究一下java String的intern
String.intern()
java.base/java/lang/String.java
public final class String implements java.io.Serializable, Comparable<String>, CharSequence, Constable, ConstantDesc { //...... /** * Returns a canonical representation for the string object. * <p> * A pool of strings, initially empty, is maintained privately by the * class {@code String}. * <p> * When the intern method is invoked, if the pool already contains a * string equal to this {@code String} object as determined by * the {@link #equals(Object)} method, then the string from the pool is * returned. Otherwise, this {@code String} object is added to the * pool and a reference to this {@code String} object is returned. * <p> * It follows that for any two strings {@code s} and {@code t}, * {@code s.intern() == t.intern()} is {@code true} * if and only if {@code s.equals(t)} is {@code true}. * <p> * All literal strings and string-valued constant expressions are * interned. String literals are defined in section 3.10.5 of the * <cite>The Java™ Language Specification</cite>. * * @return a string that has the same contents as this string, but is * guaranteed to be from a pool of unique strings. * @jls 3.10.5 String Literals */ public native String intern(); //...... }
- 當(dāng)調(diào)用intern方法時(shí),如果常量池已經(jīng)包含一個(gè)equals此String對(duì)象的字符串,則返回池中的字符串
- 當(dāng)調(diào)用intern方法時(shí),如果常量池沒有一個(gè)equals此String對(duì)象的字符串,將此String對(duì)象添加到池中,并返回此String對(duì)象的引用(即intern方法返回指向heap中的此String對(duì)象引用)
- 所有l(wèi)iteral strings及string-valued constant expressions都是interned的
實(shí)例
基于jdk12
StringExistInPoolBeforeIntern
public class StringExistInPoolBeforeIntern { public static void main(String[] args){ String stringObject = new String("tomcat"); //NOTE 在intern之前,string table已經(jīng)有了tomcat,因而intern返回tomcat,不會(huì)指向stringObject stringObject.intern(); String stringLiteral = "tomcat"; System.out.println(stringObject == stringLiteral); //false } }
- tomcat這個(gè)literal string是interned過的,常量池沒有tomcat,因而添加到常量池,常量池有個(gè)tomcat;另外由于stringObject是new的,所以heap中也有一個(gè)tomcat,而此時(shí)它指向heap中的tomcat
- stringObject.intern()返回的是heap中常量池的tomcat;stringLiteral是tomcat這個(gè)literal string,由于常量池已經(jīng)有該值,因而stringLiteral指向的是heap中常量池的tomcat
- 此時(shí)stringObject指向的是heap中的tomcat,而stringLiteral是heap中常量池的tomcat,因而二者不等,返回false
StringNotExistInPoolBeforeIntern
public class StringNotExistInPoolBeforeIntern { public static void main(String[] args){ String stringObject = new String("tom") + new String("cat"); //NOTE 在intern之前,string table沒有tomcat,因而intern指向stringObject stringObject.intern(); String stringLiteral = "tomcat"; System.out.println(stringObject == stringLiteral); //true } }
- tom及cat這兩個(gè)literal string是interned過的,常量池沒有tom及cat,因而添加到常量池,常量池有tom、cat;另外由于stringObject是new出來的,是tom及cat二者concat,因而heap中有一個(gè)tomcat
- stringObject的intern方法執(zhí)行的時(shí)候,由于常量池中沒有tomcat,因而添加到常量池,intern()返回的是指向heap中的tomcat的引用;stringLiteral是tomcat這個(gè)literal string,由于stringObject.intern()已經(jīng)將tomcat添加到常量池了并指向heap中的tomcat的引用,所以stringLiteral返回的是指向heap中的tomcat的引用
- 由于stringLiteral返回的是指向heap中的tomcat的引用,其實(shí)就是stringObject,因而二者相等,返回true
javap
基于jdk12
StringExistInPoolBeforeIntern
javac src/main/java/com/example/javac/StringExistInPoolBeforeIntern.java javap -v src/main/java/com/example/javac/StringExistInPoolBeforeIntern.class Last modified 2019年4月6日; size 683 bytes MD5 checksum 207635ffd7560f1df24b98607e2ca7db Compiled from "StringExistInPoolBeforeIntern.java" public class com.example.javac.StringExistInPoolBeforeIntern minor version: 0 major version: 56 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #8 // com/example/javac/StringExistInPoolBeforeIntern super_class: #9 // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 1 Constant pool: #1 = Methodref #9.#21 // java/lang/Object."<init>":()V #2 = Class #22 // java/lang/String #3 = String #23 // tomcat #4 = Methodref #2.#24 // java/lang/String."<init>":(Ljava/lang/String;)V #5 = Methodref #2.#25 // java/lang/String.intern:()Ljava/lang/String; #6 = Fieldref #26.#27 // java/lang/System.out:Ljava/io/PrintStream; #7 = Methodref #18.#28 // java/io/PrintStream.println:(Z)V #8 = Class #29 // com/example/javac/StringExistInPoolBeforeIntern #9 = Class #30 // java/lang/Object #10 = Utf8 <init> #11 = Utf8 ()V #12 = Utf8 Code #13 = Utf8 LineNumberTable #14 = Utf8 main #15 = Utf8 ([Ljava/lang/String;)V #16 = Utf8 StackMapTable #17 = Class #31 // "[Ljava/lang/String;" #18 = Class #32 // java/io/PrintStream #19 = Utf8 SourceFile #20 = Utf8 StringExistInPoolBeforeIntern.java #21 = NameAndType #10:#11 // "<init>":()V #22 = Utf8 java/lang/String #23 = Utf8 tomcat #24 = NameAndType #10:#33 // "<init>":(Ljava/lang/String;)V #25 = NameAndType #34:#35 // intern:()Ljava/lang/String; #26 = Class #36 // java/lang/System #27 = NameAndType #37:#38 // out:Ljava/io/PrintStream; #28 = NameAndType #39:#40 // println:(Z)V #29 = Utf8 com/example/javac/StringExistInPoolBeforeIntern #30 = Utf8 java/lang/Object #31 = Utf8 [Ljava/lang/String; #32 = Utf8 java/io/PrintStream #33 = Utf8 (Ljava/lang/String;)V #34 = Utf8 intern #35 = Utf8 ()Ljava/lang/String; #36 = Utf8 java/lang/System #37 = Utf8 out #38 = Utf8 Ljava/io/PrintStream; #39 = Utf8 println #40 = Utf8 (Z)V { public com.example.javac.StringExistInPoolBeforeIntern(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 8: 0 public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=3, args_size=1 0: new #2 // class java/lang/String 3: dup 4: ldc #3 // String tomcat 6: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V 9: astore_1 10: aload_1 11: invokevirtual #5 // Method java/lang/String.intern:()Ljava/lang/String; 14: pop 15: ldc #3 // String tomcat 17: astore_2 18: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream; 21: aload_1 22: aload_2 23: if_acmpne 30 26: iconst_1 27: goto 31 30: iconst_0 31: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V 34: return LineNumberTable: line 11: 0 line 13: 10 line 14: 15 line 15: 18 line 16: 34 StackMapTable: number_of_entries = 2 frame_type = 255 /* full_frame */ offset_delta = 30 locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String ] stack = [ class java/io/PrintStream ] frame_type = 255 /* full_frame */ offset_delta = 0 locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String ] stack = [ class java/io/PrintStream, int ] } SourceFile: "StringExistInPoolBeforeIntern.java"
- 可以看到常量池有個(gè)tomcat
StringNotExistInPoolBeforeIntern
javac src/main/java/com/example/javac/StringNotExistInPoolBeforeIntern.java javap -v src/main/java/com/example/javac/StringNotExistInPoolBeforeIntern.class Last modified 2019年4月6日; size 1187 bytes MD5 checksum 6d173f303b61b8f5826e54bb6ed5157c Compiled from "StringNotExistInPoolBeforeIntern.java" public class com.example.javac.StringNotExistInPoolBeforeIntern minor version: 0 major version: 56 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #11 // com/example/javac/StringNotExistInPoolBeforeIntern super_class: #12 // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 3 Constant pool: #1 = Methodref #12.#24 // java/lang/Object."<init>":()V #2 = Class #25 // java/lang/String #3 = String #26 // tom #4 = Methodref #2.#27 // java/lang/String."<init>":(Ljava/lang/String;)V #5 = String #28 // cat #6 = InvokeDynamic #0:#32 // #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; #7 = Methodref #2.#33 // java/lang/String.intern:()Ljava/lang/String; #8 = String #34 // tomcat #9 = Fieldref #35.#36 // java/lang/System.out:Ljava/io/PrintStream; #10 = Methodref #21.#37 // java/io/PrintStream.println:(Z)V #11 = Class #38 // com/example/javac/StringNotExistInPoolBeforeIntern #12 = Class #39 // java/lang/Object #13 = Utf8 <init> #14 = Utf8 ()V #15 = Utf8 Code #16 = Utf8 LineNumberTable #17 = Utf8 main #18 = Utf8 ([Ljava/lang/String;)V #19 = Utf8 StackMapTable #20 = Class #40 // "[Ljava/lang/String;" #21 = Class #41 // java/io/PrintStream #22 = Utf8 SourceFile #23 = Utf8 StringNotExistInPoolBeforeIntern.java #24 = NameAndType #13:#14 // "<init>":()V #25 = Utf8 java/lang/String #26 = Utf8 tom #27 = NameAndType #13:#42 // "<init>":(Ljava/lang/String;)V #28 = Utf8 cat #29 = Utf8 BootstrapMethods #30 = MethodHandle 6:#43 // REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; #31 = String #44 // \u0001\u0001 #32 = NameAndType #45:#46 // makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; #33 = NameAndType #47:#48 // intern:()Ljava/lang/String; #34 = Utf8 tomcat #35 = Class #49 // java/lang/System #36 = NameAndType #50:#51 // out:Ljava/io/PrintStream; #37 = NameAndType #52:#53 // println:(Z)V #38 = Utf8 com/example/javac/StringNotExistInPoolBeforeIntern #39 = Utf8 java/lang/Object #40 = Utf8 [Ljava/lang/String; #41 = Utf8 java/io/PrintStream #42 = Utf8 (Ljava/lang/String;)V #43 = Methodref #54.#55 // java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; #44 = Utf8 \u0001\u0001 #45 = Utf8 makeConcatWithConstants #46 = Utf8 (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; #47 = Utf8 intern #48 = Utf8 ()Ljava/lang/String; #49 = Utf8 java/lang/System #50 = Utf8 out #51 = Utf8 Ljava/io/PrintStream; #52 = Utf8 println #53 = Utf8 (Z)V #54 = Class #56 // java/lang/invoke/StringConcatFactory #55 = NameAndType #45:#60 // makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; #56 = Utf8 java/lang/invoke/StringConcatFactory #57 = Class #62 // java/lang/invoke/MethodHandles$Lookup #58 = Utf8 Lookup #59 = Utf8 InnerClasses #60 = Utf8 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; #61 = Class #63 // java/lang/invoke/MethodHandles #62 = Utf8 java/lang/invoke/MethodHandles$Lookup #63 = Utf8 java/lang/invoke/MethodHandles { public com.example.javac.StringNotExistInPoolBeforeIntern(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 8: 0 public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=3, args_size=1 0: new #2 // class java/lang/String 3: dup 4: ldc #3 // String tom 6: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V 9: new #2 // class java/lang/String 12: dup 13: ldc #5 // String cat 15: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V 18: invokedynamic #6, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; 23: astore_1 24: aload_1 25: invokevirtual #7 // Method java/lang/String.intern:()Ljava/lang/String; 28: pop 29: ldc #8 // String tomcat 31: astore_2 32: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream; 35: aload_1 36: aload_2 37: if_acmpne 44 40: iconst_1 41: goto 45 44: iconst_0 45: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V 48: return LineNumberTable: line 11: 0 line 13: 24 line 14: 29 line 15: 32 line 16: 48 StackMapTable: number_of_entries = 2 frame_type = 255 /* full_frame */ offset_delta = 44 locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String ] stack = [ class java/io/PrintStream ] frame_type = 255 /* full_frame */ offset_delta = 0 locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String ] stack = [ class java/io/PrintStream, int ] } SourceFile: "StringNotExistInPoolBeforeIntern.java" InnerClasses: public static final #58= #57 of #61; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles BootstrapMethods: 0: #30 REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; Method arguments: #31 \u0001\u0001
可以看到常量池有tom、cat、tomcat
小結(jié)
當(dāng)調(diào)用intern方法時(shí),如果常量池已經(jīng)包含一個(gè)equals此String對(duì)象的字符串,則返回池中的字符串
當(dāng)調(diào)用intern方法時(shí),如果常量池沒有一個(gè)equals此String對(duì)象的字符串,將此String對(duì)象添加到池中,并返回此String對(duì)象的引用(即intern方法返回指向heap中的此String對(duì)象引用)
所有l(wèi)iteral strings及string-valued constant expressions都是interned的
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
SpringBoot整合Hibernate Validator實(shí)現(xiàn)參數(shù)驗(yàn)證功能
這篇文章主要介紹了SpringBoot整合Hibernate Validator實(shí)現(xiàn)參數(shù)驗(yàn)證功能,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06總結(jié)Junit4,Junit5,Jupiter之間的聯(lián)系
Jupiter和Junit5之間有什么聯(lián)系?Jupiter提供了哪些新的測(cè)試方法?如何用IDEA和Jupiter生成可讀性更好的測(cè)試報(bào)告?文中有非常詳細(xì)的說明,需要的朋友可以參考下2021-06-06Java定時(shí)任務(wù):利用java Timer類實(shí)現(xiàn)定時(shí)執(zhí)行任務(wù)的功能
本篇文章主要介紹了利用java Timer類實(shí)現(xiàn)定時(shí)執(zhí)行任務(wù)的功能,具有一定的參考價(jià)值,有需要的可以了解一下。2016-11-11Java中將接口返回的字節(jié)串轉(zhuǎn)為文件詳解
這篇文章主要給大家介紹了關(guān)于Java中將接口返回的字節(jié)串轉(zhuǎn)為文件的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-11-11利用Sharding-Jdbc進(jìn)行分庫分表的操作代碼
sharding-jdbc是一個(gè)分布式的關(guān)系型數(shù)據(jù)庫中間件,今天通過本文給大家介紹利用Sharding-Jdbc進(jìn)行分庫分表的操作代碼,代碼簡(jiǎn)單易懂對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2022-01-01Spring 面向切面編程AOP實(shí)現(xiàn)詳解
這篇文章主要介紹了Spring 面向切面編程AOP實(shí)現(xiàn)詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09idea中如何創(chuàng)建scala項(xiàng)目
idea中創(chuàng)建scala項(xiàng)目有三種方式1.通過maven;2.通過idea;3.通過sbt的方式;本文就每種方法通過圖文并茂的形式給大家詳細(xì)介紹,需要的朋友參考下吧2021-07-07Java對(duì)象Serializable接口實(shí)現(xiàn)詳解
這篇文章主要介紹了Java對(duì)象Serializable接口實(shí)現(xiàn)詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12