菜鸟教程 -- 学的不仅是技术,更是梦想!

Java 教程
(追記) (追記ここまで)

Java intern() 方法

Java String类Java String类


intern() 方法用于在运行时将字符串添加到内部的字符串池中,并返回字符串池中的引用。

当调用 intern() 方法时,如果字符串常量池已经包含该字符串,则返回池中的引用,如果池中没有该字符串,则将其添加到池中,并返回该字符串的引用。

intern() 方法遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。

String s1 = new String("Hello");
String s2 = "Hello";
String s3 = s1.intern();
System.out.println(s1 == s2); // false
System.out.println(s2 == s3); // true

语法

public String intern()

参数

返回值

intern() 方法的返回值是字符串在字符串常量池(String Pool)中的引用。

返回值规则:

  • 如果字符串常量池已存在该字符串:返回池中已有字符串的引用。
  • 如果字符串常量池不存在该字符串:将当前堆中的字符串引用存入常量池(而非创建新对象),并返回该引用。

Java 版本差异:

  • 在 JDK 6 及之前,字符串常量池存储在方法区(永久代),容量有限,过多使用 intern() 可能导致 OutOfMemoryError。

  • JDK 7 及以上,字符串常量池移动到了堆内存,可以存储更多数据。

实例

以下实例演示了intern() 方法的应用:

实例

public class RunoobTest {
public static void main(String args[]) {
// str1 直接赋值字符串字面量 "Runoob",它存储在字符串常量池(String Pool)中
String str1 = "Runoob";

// str2 使用 new 关键字创建,它存储在堆(Heap)内存中
String str2 = new String("Runoob");

// str3 是 str2 调用 intern() 方法后得到的引用
// intern() 方法会将 "Runoob" 放入字符串常量池,并返回池中的引用
String str3 = str2.intern();

// str1 和 str2 比较
// str1 指向常量池中的 "Runoob",str2 指向的是堆内存中的对象
// 由于它们的地址不同,结果为 false
System.out.println(str1 == str2); // false

// str1 和 str3 比较
// str3 是 str2 调用 intern() 方法后返回的引用,它指向常量池中的 "Runoob"
// 而 str1 也是指向常量池中的 "Runoob",因此它们的地址相同,结果为 true
System.out.println(str1 == str3); // true
}
}

代码说明:

String str1 = "Runoob";

  • 直接赋值字符串字面量 "Runoob",它会自动存储在字符串常量池(String Pool)中。

String str2 = new String("Runoob");

  • 由于使用 new 关键字,它会在堆(Heap)中创建一个新的字符串对象,即 str2 不指向常量池,而是指向一个新的内存地址。

String str3 = str2.intern();

  • intern() 方法检查字符串 "Runoob" 是否已经存在于字符串常量池:

    • 如果存在,返回该字符串的引用;

    • 如果不存在,则将其添加到常量池并返回池中的引用。

  • 由于 str1 已经在常量池中,str3str1 指向同一个对象。

System.out.println(str1 == str2);

  • str1 指向常量池,str2 指向堆中的对象,所以 == 比较的是不同的内存地址,结果 false

System.out.println(str1 == str3);

  • str3 经过 intern() 之后,指向常量池中的字符串,与 str1 指向相同的对象,结果 true

以上程序执行结果为:

false
true

Java String类Java String类

AI 思考中...

1 篇笔记 写笔记

  1. #0

    尽管在输出中调用intern方法并没有什么效果,但是实际上后台这个方法会做一系列的动作和操作。在调用"ab".intern()方法的时候会返回"ab",但是这个方法会首先检查字符串池中是否有"ab"这个字符串,如果存在则返回这个字符串的引用,否则就将这个字符串添加到字符串池中,然会返回这个字符串的引用。

    可以看下面一个范例:

    String str1 = "a";
    String str2 = "b";
    String str3 = "ab";
    String str4 = str1 + str2;
    String str5 = new String("ab");
     
    System.out.println(str5.equals(str3));
    System.out.println(str5 == str3);
    System.out.println(str5.intern() == str3);
    System.out.println(str5.intern() == str4);

    得到的结果:

    true
    false
    true
    false

    为什么会得到这样的一个结果呢?我们一步一步的分析。

    • 第一、str5.equals(str3)这个结果为true,不用太多的解释,因为字符串的值的内容相同。
    • 第二、str5 == str3对比的是引用的地址是否相同,由于str5采用new String方式定义的,所以地址引用一定不相等。所以结果为false。
    • 第三、当str5调用intern的时候,会检查字符串池中是否含有该字符串。由于之前定义的str3已经进入字符串池中,所以会得到相同的引用。
    • 第四,当str4 = str1 + str2后,str4的值也为"ab",但是为什么这个结果会是false呢?先看下面代码:
    String a = new String("ab");
    String b = new String("ab");
    String c = "ab";
    String d = "a" + "b";
    String e = "b";
    String f = "a" + e;
    System.out.println(b.intern() == a);
    System.out.println(b.intern() == c);
    System.out.println(b.intern() == d);
    System.out.println(b.intern() == f);
    System.out.println(b.intern() == a.intern());

    运行结果:

    false
    true
    true
    false
    true

    由运行结果可以看出来,b.intern() == a和b.intern() == c可知,采用new 创建的字符串对象不进入字符串池,并且通过b.intern() == d和b.intern() == f可知,字符串相加的时候,都是静态字符串的结果会添加到字符串池,如果其中含有变量(如f中的e)则不会进入字符串池中。但是字符串一旦进入字符串池中,就会先查找池中有无此对象。如果有此对象,则让对象引用指向此对象。如果无此对象,则先创建此对象,再让对象引用指向此对象。

    当研究到这个地方的时候,突然想起来经常遇到的一个比较经典的Java问题,就是对比equal和==的区别,当时记得老师只是说"=="判断的是"地址",但是并没说清楚什么时候会有地址相等的情况。现在看来,在定义变量的时候赋值,如果赋值的是静态的字符串,就会执行进入字符串池的操作,如果池中含有该字符串,则返回引用。

    执行下面的代码:

    String a = "abc";
    String b = "abc";
    String c = "a" + "b" + "c";
    String d = "a" + "bc";
    String e = "ab" + "c";
     
    System.out.println(a == b);
    System.out.println(a == c);
    System.out.println(a == d);
    System.out.println(a == e);
    System.out.println(c == d);
    System.out.println(c == e);

    运行的结果:

    true
    true
    true
    true
    true
    true
    
    9年前 (2017年08月28日)

点我分享笔记

  • 昵称 (必填)
  • 邮箱 (必填)
  • 引用地址

AltStyle によって変換されたページ (->オリジナル) /