百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

聊聊java String的intern

toyiye 2024-05-19 19:36 16 浏览 0 评论

本文主要研究一下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的

doc

  • 浅谈String的intern
  • Why does String.intern() return different results under JDK8 and JDK9?
  • How to Initialize and Compare Strings in Java?
  • Difference between String literal and New String object in Java
  • 聊聊jvm的PermGen与Metaspace
  • Guide to Java String Pool
  • String Literal Vs String Object in Java

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码