什么是字符串常量池?

什么是字符串常量池?

在理解字符串常量前,我们先熟悉一下如何创建一个字符串,在Java中有两种方法可以创建一个字符串对象:

  • 使用new运算符。例如:

1

String str = new String("Hello");

  • 使用字符串常量或者常量表达式。例如:

1

2

String str="Hello"; //(字符串常量) 或者

String str="Hel" + "lo"; //(字符串常量表达式).

这些字符串的创建方式之间有什么区别呢?在Java中,equals方法被认为是对象的值进行深层次的比较,而操作符==是进行的浅层次的比较。 equals方法比较两个对象的内容而不是引用。==两侧是引用类型(例如对象)时,如果引用是相同的-即指向同一个对象-则执行结果为真。如果是值类型 (例如原生类型),如果值相同,则执行结果为真。equals方法在两个对象具有相同内容时返回真-但是,java.lang.Object类中的 equals方法返回真-如果类没有覆盖默认的equals方法,如果两个引用指向同一个对象。

让我们通过下面的例子来看看这两种字符串的创建方式之间有什么区别吧。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

public class DemoStringCreation {

    public static void main(String args[]) {

        String str1 = "Hello";

        String str2 = "Hello";

        System.out.println("str1 and str2 are created by using string literal.");

        System.out.println("    str1 == str2 is " + (str1 == str2));

        System.out.println("    str1.equals(str2) is " + str1.equals(str2)); 

        String str3 = new String("Hello");

        String str4 = new String("Hello");

        System.out.println("str3 and str4 are created by using new operator.");

        System.out.println("    str3 == str4 is " + (str3 == str4));

        System.out.println("    str3.equals(str4) is " + str3.equals(str4)); 

        String str5 = "Hel" + "lo";

        String str6 = "He" + "llo";

        System.out.println("str5 and str6 are created by using string constant expression.");

        System.out.println("    str5 == str6 is " + (str5 == str6));

        System.out.println("    str5.equals(str6) is " + str5.equals(str6)); 

        String s = "lo";

        String str7 = "Hel" + s;

        String str8 = "He" + "llo";

        System.out.println("str7 is computed at runtime.");

        System.out.println("str8 is created by using string constant expression.");

        System.out.println("    str7 == str8 is " + (str7 == str8));

        System.out.println("    str7.equals(str8) is " + str7.equals(str8)); 

    }

}

输出结果为:


1

2

3

4

5

6

7

8

9

10

11

12

13

str1 and str2 are created by using string literal.

    str1 == str2 is true

    str1.equals(str2) is true

str3 and str4 are created by using new operator.

    str3 == str4 is false

    str3.equals(str4) is true

str5 and str6 are created by using string constant expression.

    str5 == str6 is true

    str5.equals(str6) is true

str7 is computed at runtime.

str8 is created by using string constant expression.

    str7 == str8 is false

    str7.equals(str8) is true

使用相同的字符序列而不是使用new关键字创建的两个字符串会创建指向Java字符串常量池中的同一个字符串的指针。字符串常量池是Java节约资源的一种方式。

字符串常量池

字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价。JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化。为 了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串池,每当代码创建字符串常量时,JVM会首先检查字符串常量池。如果字符串已经存在池中, 就返回池中的实例引用。如果字符串不在池中,就会实例化一个字符串并放到池中。Java能够进行这样的优化是因为字符串是不可变的,可以不用担心数据冲突 进行共享。例如:


1

2

3

4

5

6

7

8

9

public class Program

{

    public static void main(String[] args)

    {

       String str1 = "Hello"

       String str2 = "Hello";

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

    }

}

其结果是:


1

true

不幸的是,当使用:


1

String a=new String("Hello");

一个字符串对象在字符串常量池外创建,即使池里存在相同的字符串。考虑到这些,要避免new一个字符串除非你明确的知道需要这么做!例如:


1

2

3

4

5

6

7

8

9

10

public class Program

{

    public static void main(String[] args)

    {

       String str1 = "Hello"

       String str2 = new String("Hello");

       System.out.print(str1 == str2 + " ");

       System.out.print(str1.equals(str2));

    }

}

结果是:


1

false true

JVM中有一个常量池,任何字符串至多维护一个对象。字符串常量总是指向字符串池中的一个对象。通过new操作符创建的字符串对象不指向字符串池中 的任何对象,但是可以通过使用字符串的intern()方法来指向其中的某一个。java.lang.String.intern()返回一个保留池字符 串,就是一个在全局字符串池中有了一个入口。如果以前没有在全局字符串池中,那么它就会被添加到里面。例如:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

public class Program

{

    public static void main(String[] args)

    {

        // Create three strings in three different ways.

        String s1 = "Hello";

        String s2 = new StringBuffer("He").append("llo").toString();

        String s3 = s2.intern();

        // Determine which strings are equivalent using the ==

        // operator

        System.out.println("s1 == s2? " + (s1 == s2));

        System.out.println("s1 == s3? " + (s1 == s3));

    }

}

输出是:


1

2

s1 == s2? false

s1 == s3? true

//intern() 返回字符串对象的规范化表示形式。也就是把对象转化成字符串常量

为了优化空间,运行时实例创建的全局字符串常量池中有一个表,总是为池中每个唯一的字符串对象维护一个引用。这就意味着它们一直引用着字符串常量池中的对象,所以,在常量池中的这些字符串不会被垃圾收集器回收。

Java语言规范第三版中的字符串常量

每一个字符串常量都是指向一个字符串类实例的引用。字符串对象有一个固定值。字符串常量,或者一般的说,常量表达式中的字符串都被使用方法 String.intern进行保留来共享唯一的实例。


1

2

3

4

5

6

7

8

9

10

11

12

13

package testPackage;

class Test {

        public static void main(String[] args) {

                String hello = "Hello", lo = "lo";

                System.out.print((hello == "Hello") + " ");

                System.out.print((Other.hello == hello) + " ");

                System.out.print((other.Other.hello == hello) + " ");

                System.out.print((hello == ("Hel"+"lo")) + " ");

                System.out.print((hello == ("Hel"+lo)) + " ");

                System.out.println(hello == ("Hel"+lo).intern());

        }

}

class Other { static String hello = "Hello"; }

编译单元:


1

2

package other;

public class Other { static String hello = "Hello"; }

产生输出:


1

true true true true false true

这个例子说明了六点:

  • 同一个包下同一个类中的字符串常量的引用指向同一个字符串对象;
  • 同一个包下不同的类中的字符串常量的引用指向同一个字符串对象;
  • 不同的包下不同的类中的字符串常量的引用仍然指向同一个字符串对象;
  • 由常量表达式计算出的字符串在编译时进行计算,然后被当作常量;
  • 在运行时通过连接计算出的字符串是新创建的,因此是不同的;
  • 通过计算生成的字符串显示调用intern方法后产生的结果与原来存在的同样内容的字符串常量是一样的。

原文链接: xyzws 翻译: ImportNew.com - lumeng689
译文链接: http://www.importnew.com/10756.html
[ 转载请保留原文出处、译者和译文链接。]

时间: 2024-10-11 01:50:54

什么是字符串常量池?的相关文章

Java中的字符串常量池

最近做到一个题目: 问题:String str = new String("abc"),"abc"在内存中是怎么分配的?    答案是:堆,字符串常量区. 题目考查的为Java中的字符串常量池和JVM运行时数据区的相关概念."abc"为字面量对象,其存储在堆内存中.而字符串常量池则存储的是字符串对象的一个引用. Java中的字符串常量池 Java中字符串对象创建有两种形式,一种为字面量形式,如String str = "droid&qu

string字符串常量池在内存中的位置

这里仅仅是举个简单的样例说明字符串常量池在内存中的位置. 闲言少叙,直接上代码. Java代码   <span style="font-size: large;">import java.util.ArrayList; public class Test { public static void main(String[] args) { String str = "abc"; char[] array = {'a', 'b', 'c'}; String

字符串常量池、堆、栈

String a="a"+"b"+"c" 创建了几个对象 这个问题涉及到了字符串常量池和字符串拼接 String a="a"+"b"+"c" 通过编译器优化后,得到的效果是 String a="abc" Java中字符串对象创建有两种形式,一种为字面量形式,如String str = "droid"; 另一种就是使用new这种标准的构造对象的方法,

C#之CLR内存字符串常量池(string)

C#之CLR内存字符串常量池(string) 投稿:shichen2014 字体:[增加 减小] 类型:转载 时间:2014-08-04我要评论 这篇文章主要介绍了C#之CLR内存字符串常量池(string),对于学习和理解C#内存原理很有帮助,需要的朋友可以参考下 C#中的string是比特殊的类,说引用类型,但不存在堆里面,而且String str=new String("HelloWorld")这样的重装也说没有的. 我们先来看一个方法: ? 1 2 3 4 5 6 7 8 cl

对于JVM中方法区,永久代,元空间以及字符串常量池的迁移和string.intern方法

在Java虚拟机(以下简称JVM)中,类包含其对应的元数据,比如类的层级信息,方法数据和方法信息(如字节码,栈和变量大小),运行时常量池,已确定的符号引用和虚方法表. 在过去(当自定义类加载器使用不普遍的时候),类几乎是"静态的"并且很少被卸载和回收,因此类也可以被看成"永久的".另外由于类作为JVM实现的一部分,它们不由程序来创建,因为它们也被认为是"非堆"的内存. 在JDK8之前的HotSpot虚拟机中,类的这些"永久的"

java字符串常量池

卧虎藏龙,是一款手机3D游戏.其效果和Pc端3D效果类似,个人感觉还是很好的. 之前曾经看过一个卧虎藏龙的轻功视频,视频内容是从武当山广场开始起跳,施展轻功一直飞到山脚下的视频.之后我对卧虎藏龙就一直很期待. 但是这次封测我只升到了24级,封测便停了,并没有玩到可以施展轻功的地步,或者我没有掌握技巧,这是一个小的遗憾. 因为之前玩Pc游戏刀剑/  剑侠情缘三,就是看中了其中的轻功系统.而卧虎藏龙的轻功操作更让人有玩的冲动,文学功底不行,所以不会描述,大家可以百度一下这个轻功视频:http://1

转载:Java中的字符串常量池详细介绍

引用自:http://blog.csdn.net/langhong8/article/details/50938041 这篇文章主要介绍了Java中的字符串常量池详细介绍,JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池,需要的朋友可以参考下 Java中字符串对象创建有两种形式,一种为字面量形式,如String str = "droid";,另一种就是使用new这种标准的构造对象的方法,如String str = new Stri

常量池之字符串常量池String.intern()

运行时常量池是方法区(PermGen)的一部分. 需要提前了解: 1. JVM内存模型. 2. JAVA对象在JVM中内存分配 常量池的好处 常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享. - Java的自动装箱中其实就使用到了运行时常量池.详见:Java 自动装箱与拆箱的实现原理 - 还有字符串常量池. 字符串进入到常量池的两种方法: 1. new String()的实例调用intern()方法. ????执行intern()方法时,若常量池中不存在等值的字符串,JV

Java字符串常量池是什么?为什么要有这种常量池?

简单介绍 Java中的字符串常量池(String Pool)是存储在Java堆内存中的字符串池.我们知道String是java中比较特殊的类,我们可以使用new运算符创建String对象,也可以用双引号("")创建字串对象. Java中的字符串常量池 下图,清楚地解释了如何在Java堆内存中维护字符串常量池,以及当我们使用不同的方式创建字符串时在堆内存中如何存放. 之所以有字符串常量池,是因为String在Java中是不可变(immutable)的,它是String interning