关于java String中intern的深入讲解
序
本文主要研究一下javaString的intern
String.intern()
java.base/java/lang/String.java
publicfinalclassString implementsjava.io.Serializable,Comparable,CharSequence, Constable,ConstantDesc{ //...... /** *Returnsacanonicalrepresentationforthestringobject. * *Apoolofstrings,initiallyempty,ismaintainedprivatelybythe *class{@codeString}. *
*Whentheinternmethodisinvoked,ifthepoolalreadycontainsa *stringequaltothis{@codeString}objectasdeterminedby *the{@link#equals(Object)}method,thenthestringfromthepoolis *returned.Otherwise,this{@codeString}objectisaddedtothe *poolandareferencetothis{@codeString}objectisreturned. *
*Itfollowsthatforanytwostrings{@codes}and{@codet}, *{@codes.intern()==t.intern()}is{@codetrue} *ifandonlyif{@codes.equals(t)}is{@codetrue}. *
*Allliteralstringsandstring-valuedconstantexpressionsare *interned.Stringliteralsaredefinedinsection3.10.5ofthe *TheJava™LanguageSpecification. * *@returnastringthathasthesamecontentsasthisstring,butis *guaranteedtobefromapoolofuniquestrings. *@jls3.10.5StringLiterals */ publicnativeStringintern(); //...... }
- 当调用intern方法时,如果常量池已经包含一个equals此String对象的字符串,则返回池中的字符串
- 当调用intern方法时,如果常量池没有一个equals此String对象的字符串,将此String对象添加到池中,并返回此String对象的引用(即intern方法返回指向heap中的此String对象引用)
- 所有literalstrings及string-valuedconstantexpressions都是interned的
实例
基于jdk12
StringExistInPoolBeforeIntern
publicclassStringExistInPoolBeforeIntern{ publicstaticvoidmain(String[]args){ StringstringObject=newString("tomcat"); //NOTE在intern之前,stringtable已经有了tomcat,因而intern返回tomcat,不会指向stringObject stringObject.intern(); StringstringLiteral="tomcat"; System.out.println(stringObject==stringLiteral);//false } }
- tomcat这个literalstring是interned过的,常量池没有tomcat,因而添加到常量池,常量池有个tomcat;另外由于stringObject是new的,所以heap中也有一个tomcat,而此时它指向heap中的tomcat
- stringObject.intern()返回的是heap中常量池的tomcat;stringLiteral是tomcat这个literalstring,由于常量池已经有该值,因而stringLiteral指向的是heap中常量池的tomcat
- 此时stringObject指向的是heap中的tomcat,而stringLiteral是heap中常量池的tomcat,因而二者不等,返回false
StringNotExistInPoolBeforeIntern
publicclassStringNotExistInPoolBeforeIntern{ publicstaticvoidmain(String[]args){ StringstringObject=newString("tom")+newString("cat"); //NOTE在intern之前,stringtable没有tomcat,因而intern指向stringObject stringObject.intern(); StringstringLiteral="tomcat"; System.out.println(stringObject==stringLiteral);//true } }
- tom及cat这两个literalstring是interned过的,常量池没有tom及cat,因而添加到常量池,常量池有tom、cat;另外由于stringObject是new出来的,是tom及cat二者concat,因而heap中有一个tomcat
- stringObject的intern方法执行的时候,由于常量池中没有tomcat,因而添加到常量池,intern()返回的是指向heap中的tomcat的引用;stringLiteral是tomcat这个literalstring,由于stringObject.intern()已经将tomcat添加到常量池了并指向heap中的tomcat的引用,所以stringLiteral返回的是指向heap中的tomcat的引用
- 由于stringLiteral返回的是指向heap中的tomcat的引用,其实就是stringObject,因而二者相等,返回true
javap
基于jdk12
StringExistInPoolBeforeIntern
javacsrc/main/java/com/example/javac/StringExistInPoolBeforeIntern.java javap-vsrc/main/java/com/example/javac/StringExistInPoolBeforeIntern.class Lastmodified2019年4月6日;size683bytes MD5checksum207635ffd7560f1df24b98607e2ca7db Compiledfrom"StringExistInPoolBeforeIntern.java" publicclasscom.example.javac.StringExistInPoolBeforeIntern minorversion:0 majorversion: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 Constantpool: #1=Methodref#9.#21//java/lang/Object."":()V #2=Class#22//java/lang/String #3=String#23//tomcat #4=Methodref#2.#24//java/lang/String." ":(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 #11=Utf8()V #12=Utf8Code #13=Utf8LineNumberTable #14=Utf8main #15=Utf8([Ljava/lang/String;)V #16=Utf8StackMapTable #17=Class#31//"[Ljava/lang/String;" #18=Class#32//java/io/PrintStream #19=Utf8SourceFile #20=Utf8StringExistInPoolBeforeIntern.java #21=NameAndType#10:#11//" ":()V #22=Utf8java/lang/String #23=Utf8tomcat #24=NameAndType#10:#33//" ":(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=Utf8com/example/javac/StringExistInPoolBeforeIntern #30=Utf8java/lang/Object #31=Utf8[Ljava/lang/String; #32=Utf8java/io/PrintStream #33=Utf8(Ljava/lang/String;)V #34=Utf8intern #35=Utf8()Ljava/lang/String; #36=Utf8java/lang/System #37=Utf8out #38=Utf8Ljava/io/PrintStream; #39=Utf8println #40=Utf8(Z)V { publiccom.example.javac.StringExistInPoolBeforeIntern(); descriptor:()V flags:(0x0001)ACC_PUBLIC Code: stack=1,locals=1,args_size=1 0:aload_0 1:invokespecial#1//Methodjava/lang/Object." ":()V 4:return LineNumberTable: line8:0 publicstaticvoidmain(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//classjava/lang/String 3:dup 4:ldc#3//Stringtomcat 6:invokespecial#4//Methodjava/lang/String." ":(Ljava/lang/String;)V 9:astore_1 10:aload_1 11:invokevirtual#5//Methodjava/lang/String.intern:()Ljava/lang/String; 14:pop 15:ldc#3//Stringtomcat 17:astore_2 18:getstatic#6//Fieldjava/lang/System.out:Ljava/io/PrintStream; 21:aload_1 22:aload_2 23:if_acmpne30 26:iconst_1 27:goto31 30:iconst_0 31:invokevirtual#7//Methodjava/io/PrintStream.println:(Z)V 34:return LineNumberTable: line11:0 line13:10 line14:15 line15:18 line16:34 StackMapTable:number_of_entries=2 frame_type=255/*full_frame*/ offset_delta=30 locals=[class"[Ljava/lang/String;",classjava/lang/String,classjava/lang/String] stack=[classjava/io/PrintStream] frame_type=255/*full_frame*/ offset_delta=0 locals=[class"[Ljava/lang/String;",classjava/lang/String,classjava/lang/String] stack=[classjava/io/PrintStream,int] } SourceFile:"StringExistInPoolBeforeIntern.java"
- 可以看到常量池有个tomcat
StringNotExistInPoolBeforeIntern
javacsrc/main/java/com/example/javac/StringNotExistInPoolBeforeIntern.java javap-vsrc/main/java/com/example/javac/StringNotExistInPoolBeforeIntern.class Lastmodified2019年4月6日;size1187bytes MD5checksum6d173f303b61b8f5826e54bb6ed5157c Compiledfrom"StringNotExistInPoolBeforeIntern.java" publicclasscom.example.javac.StringNotExistInPoolBeforeIntern minorversion:0 majorversion: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 Constantpool: #1=Methodref#12.#24//java/lang/Object."":()V #2=Class#25//java/lang/String #3=String#26//tom #4=Methodref#2.#27//java/lang/String." ":(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 #14=Utf8()V #15=Utf8Code #16=Utf8LineNumberTable #17=Utf8main #18=Utf8([Ljava/lang/String;)V #19=Utf8StackMapTable #20=Class#40//"[Ljava/lang/String;" #21=Class#41//java/io/PrintStream #22=Utf8SourceFile #23=Utf8StringNotExistInPoolBeforeIntern.java #24=NameAndType#13:#14//" ":()V #25=Utf8java/lang/String #26=Utf8tom #27=NameAndType#13:#42//" ":(Ljava/lang/String;)V #28=Utf8cat #29=Utf8BootstrapMethods #30=MethodHandle6:#43//REF_invokeStaticjava/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=Utf8tomcat #35=Class#49//java/lang/System #36=NameAndType#50:#51//out:Ljava/io/PrintStream; #37=NameAndType#52:#53//println:(Z)V #38=Utf8com/example/javac/StringNotExistInPoolBeforeIntern #39=Utf8java/lang/Object #40=Utf8[Ljava/lang/String; #41=Utf8java/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=Utf8makeConcatWithConstants #46=Utf8(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; #47=Utf8intern #48=Utf8()Ljava/lang/String; #49=Utf8java/lang/System #50=Utf8out #51=Utf8Ljava/io/PrintStream; #52=Utf8println #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=Utf8java/lang/invoke/StringConcatFactory #57=Class#62//java/lang/invoke/MethodHandles$Lookup #58=Utf8Lookup #59=Utf8InnerClasses #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=Utf8java/lang/invoke/MethodHandles$Lookup #63=Utf8java/lang/invoke/MethodHandles { publiccom.example.javac.StringNotExistInPoolBeforeIntern(); descriptor:()V flags:(0x0001)ACC_PUBLIC Code: stack=1,locals=1,args_size=1 0:aload_0 1:invokespecial#1//Methodjava/lang/Object." ":()V 4:return LineNumberTable: line8:0 publicstaticvoidmain(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//classjava/lang/String 3:dup 4:ldc#3//Stringtom 6:invokespecial#4//Methodjava/lang/String." ":(Ljava/lang/String;)V 9:new#2//classjava/lang/String 12:dup 13:ldc#5//Stringcat 15:invokespecial#4//Methodjava/lang/String." ":(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//Methodjava/lang/String.intern:()Ljava/lang/String; 28:pop 29:ldc#8//Stringtomcat 31:astore_2 32:getstatic#9//Fieldjava/lang/System.out:Ljava/io/PrintStream; 35:aload_1 36:aload_2 37:if_acmpne44 40:iconst_1 41:goto45 44:iconst_0 45:invokevirtual#10//Methodjava/io/PrintStream.println:(Z)V 48:return LineNumberTable: line11:0 line13:24 line14:29 line15:32 line16:48 StackMapTable:number_of_entries=2 frame_type=255/*full_frame*/ offset_delta=44 locals=[class"[Ljava/lang/String;",classjava/lang/String,classjava/lang/String] stack=[classjava/io/PrintStream] frame_type=255/*full_frame*/ offset_delta=0 locals=[class"[Ljava/lang/String;",classjava/lang/String,classjava/lang/String] stack=[classjava/io/PrintStream,int] } SourceFile:"StringNotExistInPoolBeforeIntern.java" InnerClasses: publicstaticfinal#58=#57of#61;//Lookup=classjava/lang/invoke/MethodHandles$Lookupofclassjava/lang/invoke/MethodHandles BootstrapMethods: 0:#30REF_invokeStaticjava/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; Methodarguments: #31\u0001\u0001
可以看到常量池有tom、cat、tomcat
小结
当调用intern方法时,如果常量池已经包含一个equals此String对象的字符串,则返回池中的字符串
当调用intern方法时,如果常量池没有一个equals此String对象的字符串,将此String对象添加到池中,并返回此String对象的引用(即intern方法返回指向heap中的此String对象引用)
所有literalstrings及string-valuedconstantexpressions都是interned的
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对毛票票的支持。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。