快捷搜索:  xxx  as  1111

详解Java String字符串对象的创建及管理

Constant Pool常量池的观点:

在讲到String的一些特殊环境时,总会提到String Pool或者Constant Pool,然则我想很多人都不太明白Constant Pool到底是个怎么样的器械,运行的时刻存储在哪里,以是在这里先说一下Constant Pool的内容。

String Pool是对应于在Constant Pool中存储String常量的区域。习气称为String Pool,也有人称为String Constant Pool.似乎没有正式的命名。

在java编译好的class文件中,有个区域称为Constant Pool,他是一个由数组组成的表,类型为cp_info constant_pool[],用来存储法度榜样中应用的各类常量,包括Class/String/Integer等各类基础Java数据类型。

对付Constant Pool,表的基础通用布局为:

cp_info {

u1 tag;

u1 info[];

}

tag是一个数字,用来表示存储的常量的类型,例如8表示String类型,5表示Long类型,info[]根据

类型码tag的不合会发生响应变更。

对付String类型,表的布局为:

CONSTANT_String_info {

u1 tag;

u2 string_index;

}

tag固定为8,string_index是字符串内容信息,类型为:

CONSTANT_Utf8_info {

u1 tag;

u2 length;

u1 bytes[length];

}

tag固定为1,length为字符串的长度,bytes[length]为字符串的内容。

(以下代码在jdk6中编译)

为了具体理解Constant Pool的布局,我们参看一些代码:

String s1 = "sss111";

String s2 = "sss222";

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

因为"sss111"和"sss222"都是字符串常量,在编译期就已经创建好了存储在class文件中。

在编译后的class文件中会存在这2个常量的对应表示:

08 00 11 01 00 06 73 73 73 31 31 31 08 00 13 01 ; ......sss111....

00 06 73 73 73 32 32 32; ..sss222

根据上面说的String常量布局,我们阐发一下:

开始的08为CONSTANT_String_info布局中的tag,而11应该是它的相对引用,01为CONSTANT_Utf8_info的tag,06为对应字符串的长度,73 73 73 31 31 31为字符串对应的编码,接着阐发,会发明后面的是对应"sss222"的存储布局。

颠末上面阐发,我们知道了11和13是两个字符串的相对引用,就可以改动class文件来改动打印的内容,把class文件中的00 6E 00 04 00 03 00 00 00 24 12 10 4C 12 12 4D改成00 6E 00 04 00 03 00 00 00 24 12 10 4C 12 10 4D,法度榜样就会输出sss111 sss111,而不是和原法度榜样一样输出sss111 sss222,由于我们把对"sss222"的相对引用12改成了对"sss111"的相对引用10。

public class Test {

public static void main(String[] args) {

String s1 = "sss111";

String s2 = "sss111";

}

}

在上面法度榜样中存在2个相同的常量"sss111",对付n个值相同的String常量,在Constant Pool中只会创建一个,以是在编译好的class文件中,我们只能找到一个对"sss111"的表示:

000000abh: 08 00 11 01 00 06 73 73 73 31 31 31; ......sss111

在法度榜样履行的时刻,Constant Pool会储存在Method Area,而不是heap中。

别的,对付""内容为空的字符串常量,会创建一个长度为0,内容为空的字符串放到Constant Pool中,

而且Constant Pool在运行期是可以动态扩展的。

关于String类的阐明

1.String应用private final char value[]来实现字符串的存储,也便是说String工具创建之后,就不能再改动此工具中存储的字符串内容,便是由于如斯,才说String类型是弗成变的(immutable)。

2.String类有一个特殊的创建措施,便是应用""双引号来创建.例如new String("i am")实际创建了2个String工具,一个是"i am"经由过程""双引号创建的,另一个是经由过程new创建的.只不过他们创建的时期不合, 一个是编译期,一个是运行期!

3.java对String类型重载了+操作符,可以直接应用+对两个字符串进行连接。

4.运行期调用String类的intern()措施可以向String Pool中动态添加工具。

String的创建措施一样平常有如下几种

1.直接应用""引号创建;

2.应用new String()创建;

3.应用new String("someString")创建以及其他的一些重载构造函数创建;

4.应用重载的字符串连接操作符+创建。

例1

String s1 = "sss111";

//此语句同上

String s2 = "sss111";

System.out.println(s1 == s2); //结果为true

例2

String s1 = new String("sss111");

String s2 = "sss111";

System.out.println(s1 == s2); //结果为false

例3

String s1 = new String("sss111");

s1 = s1.intern();

String s2 = "sss111";

System.out.println(s1 == s2);

例4

String s1 = new String("111");

String s2 = "sss111";

String s3 = "sss" + "111";

String s4 = "sss" + s1;

System.out.println(s2 == s3); //true

System.out.println(s2 == s4); //false

System.out.println(s2 == s4.intern()); //true

例5

这个是The Java Language Specification中3.10.5节的例子,有了上面的阐明,这个应该不难理解了

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"; }

package other;

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

输出结果为true true true true false true,请自行阐发!

结果上面阐发,总结如下:

1.零丁应用""引号创建的字符串都是常量,编译期就已经确定存储到String Pool中;

2.应用new String("")创建的工具会存储到heap中,是运行期新创建的;

3.应用只包孕常量的字符串连接符如"aa" + "aa"创建的也是常量,编译期就能确定,已经确定存储到String Pool中;

4.应用包孕变量的字符串连接符如"aa" + s1创建的工具是运行期才创建的,存储在heap中;

5.应用"aa" + s1以及new String("aa" + s1)形式创建的工具是否加入到String Pool中我不太确定,可能是必须调用intern()措施才会加入。

还有几个常常考的口试题:

1.

String s1 = new String("s1") ;

String s2 = new String("s1") ;

上面创建了几个String工具?

谜底:3个 ,编译期Constant Pool中创建1个,运行期heap中创建2个.

2.

String s1 = "s1";

String s2 = s1;

s2 = "s2";

s1指向的工具中的字符串是什么?

谜底: "s1"

您可能还会对下面的文章感兴趣: