关于java String中intern的深入讲解
作者:codecraft 发布时间:2023-01-24 18:18:36
序
本文主要研究一下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();
//......
}
当调用intern方法时,如果常量池已经包含一个equals此String对象的字符串,则返回池中的字符串
当调用intern方法时,如果常量池没有一个equals此String对象的字符串,将此String对象添加到池中,并返回此String对象的引用(即intern方法返回指向heap中的此String对象引用)
所有literal strings及string-valued constant expressions都是interned的
实例
基于jdk12
StringExistInPoolBeforeIntern
public class StringExistInPoolBeforeIntern {
public static void main(String[] args){
String stringObject = new String("tomcat");
//NOTE 在intern之前,string table已经有了tomcat,因而intern返回tomcat,不会指向stringObject
stringObject.intern();
String stringLiteral = "tomcat";
System.out.println(stringObject == stringLiteral); //false
}
}
tomcat这个literal string是interned过的,常量池没有tomcat,因而添加到常量池,常量池有个tomcat;另外由于stringObject是new的,所以heap中也有一个tomcat,而此时它指向heap中的tomcat
stringObject.intern()返回的是heap中常量池的tomcat;stringLiteral是tomcat这个literal string,由于常量池已经有该值,因而stringLiteral指向的是heap中常量池的tomcat
此时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这两个literal string是interned过的,常量池没有tom及cat,因而添加到常量池,常量池有tom、cat;另外由于stringObject是new出来的,是tom及cat二者concat,因而heap中有一个tomcat
stringObject的intern方法执行的时候,由于常量池中没有tomcat,因而添加到常量池,intern()返回的是指向heap中的tomcat的引用;stringLiteral是tomcat这个literal string,由于stringObject.intern()已经将tomcat添加到常量池了并指向heap中的tomcat的引用,所以stringLiteral返回的是指向heap中的tomcat的引用
由于stringLiteral返回的是指向heap中的tomcat的引用,其实就是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"
可以看到常量池有个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
小结
当调用intern方法时,如果常量池已经包含一个equals此String对象的字符串,则返回池中的字符串
当调用intern方法时,如果常量池没有一个equals此String对象的字符串,将此String对象添加到池中,并返回此String对象的引用(即intern方法返回指向heap中的此String对象引用)
所有literal strings及string-valued constant expressions都是interned的
来源:https://segmentfault.com/a/1190000018775484
猜你喜欢
- 该项目主要实现mybatisplus、多数据源、lombok、druid的集成主要参考 https://mp.baomidou.com/gu
- 在 javax.validation.constraints包中定义了非常多的校验注解,引入依赖:<dependency> &n
- 前言:上篇C#进阶系列——WebApi接口传参不再困惑:传参详解介绍了WebApi参数的传递,这篇来看看WebApi里面异常的处理。关于异常
- JetBrains 系列产品(IDEA、Pycharm 等)使用本站破解教程 (opens new window),在输入激活码时,部分小伙
- 文章来源:aspcn 作者:孙雯简单的WEB服务器一个简单的WEB服务器将由列表9.2这样构建.当然,还必须要对方法和回应事件进行改进.简单
- 2018年3月20日,Oracle发布java10。java10为java带来了很多新特性,其中让人眼前一亮的便是var关键字的引入。wha
- 最近由于工作要求:前端采用vue开发,后端采用springboot开发,前后端分离开发,最后前端页面又整合到后端来。经历多次采坑,总结以下方
- 问题描述:idea输入中文,没输入几个拼音就好像自动回车,有时得到几个字母,然后就不能输入拼音了。遇到这个情况就导致输入中文特别困难,可以采
- Map集合和Collection集合的区别Map集合是有Key和Value的,Collection集合是只有Value。Collection
- SpringBoot2之PUT请求接收不了参数的解决办法,这个问题,关乎两个Filter过滤器,是spring3和3.5之后提供的,目的就是
- Idea2020.2创建JavaWeb的方式略有改动,以下做个记录,大家可以参考下,对以后的工作有所帮助!1.创建项目不再是Java Ent
- resultMap的Colum和property属性1: resultMap标签当我们的数据库字段与实体类的属性不一致时,就需要使用该标签进
- 前言上一篇文章分享了Springboot项目快速实现过滤器功能,本篇文章接着来盘一盘 * ,仔细研究后会发现,其实 * 和过滤器的功能非常类
- 表单提交此处的表单时 -使用JSON.stringify()函数将数组转换成json类型提交后台,后台使用@RequestBody User
- 这周末体验了一下挺火的Docker技术,记录学习笔记。>Docker是干什么的Docker 是一个基于Linux容器(LXC-linu
- 前言此前部门内的一个线上系统上线后内存一路飙高、一段时间后直接占满。协助开发人员去分析定位,发现内存中某个Object的量远远超出了预期的范
- 背景:最近项目中涉及到自定义线程池中子线程获取父线程的traceId,这个数据的传递过程可以用lamdba表达式进行封装实现的。这让我想到s
- 一元运算符,也叫单项算符,一目运算符,一元算符 ,英文名字:UnaryOperator。描述:接受一个参数为类型T,返回值类型也为T。源码:
- 一、为何要使用netty开发由于之前已经用Java中的socket写过一版简单的聊天室,这里就不再对聊天室的具体架构进行细致的介绍了,主要关
- 冒泡排序冒泡排序的思想: 每次让当前的元素和它的下一个元素比较大小、如果前一个的元素大于后一个元素的话,交换两个元素。这样的话经历一次扫描之