在讲到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数据类型,详情参见The Java Virtual Machine Specification 4.4章节.
对于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中.
6.使用"aa" + s1以及new String("aa" + s1)形式创建的对象是否加入到String
Pool中我不太确定,可能是必须
调用intern()方法才会加入,希望高手能回答 @_@
还有个特殊发现:
String s1 = "s1" + "s2"编译后会在String Pool中加入"s1s2"和"s1"
2个常量,但是没有加入"s2",不知道是什
么规律??试了String s1 = "s1" + "s2" + "s3" +
"s4",还是只加入了"s1s2s3s4"和"s1",好像除了第一个后面的
都不加入了.
还有几个经常考的面试题:
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"
来源:http://topic.csdn.net/u/20080929/02/4E0EF626-98EE-4D6D-96ED-FE40AFE8290B.html?t=floum0ci
分享到:
相关推荐
java实现对象转化为get请求的param参数String字符串,本人自测非常好用,一般对象可以转化键值对的格式,但是最近项目需要自己手动拼接对象作为get请求的参数,百度了一堆还不如自己写一个,欢迎各位使用,有什么...
java的String字符串总有补0,绝对好用
掌握String字符串对象的创建 掌握字符串对象的输入与输出 一般程序需要处理大量文本数据Java语言的文本数据被保存为字符或字符串类型。 若干个字符在计算机里面如何存储? 如何引用呢? 引入 例如 ...
java字符串转String数组简单实例,简单但很实用
下面小编就为大家带来一篇Java中Json字符串直接转换为对象的方法(包括多层List集合)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
java String 与各种进制字符之间的转换
List集合转换成String,String转List,Map转String,String转Map等 集合与字符串相互转换,可以自己扩展源码,带有注释
Base64转String字符串,支持将Base64转化为String字符串
Java设置String字符串编码方法详解
java中String类型转换方法.pdf
概述:本文主要研究的是JAVA的字符串拼接的性能,原文中的测试代码在功能上并不等价,导致concat的测试意义不大。不过原作者在评论栏给了新的concat结果,如果有兴趣的同学建议自己修改代码测试。 在JAVA中拼接两个...
string常用截取字符串方法有很多,但是配合使用以下两种,基本都能满足要求: find(string strSub, npos); find_last_of(string strSub, npos); 其中strSub是需要寻找的子字符串,npos为查找起始位置。找到返回子...
字符串数组转换成string类型的
将string类型的xml转为JSON字符串,利用JSONObject处理JSON串
JDK1.5中,String类新增了一个很有用的静态方法,这些方法有助于开发人员对字符串的各类操作
Java中颜色的String和Color对象之间的互相转换
js date转String 日期字符串转换
Java中将字符串作为String类型对象来处理。当创建一个String对象时,被创建的字符串是不能被改变的。每次需要改变字符串时都要创建一个新的String对象来保存新的内容。原始的字符串不变。之所以采用这种方法是因为...
创建一个字符串“HelloWorld!!!”,将这个字符串拆分并转换成集合的方法。 自己也可以修改成汉字string类型。
使用Java的String类操作字符串和子串。 实验内容: 1.写一个程序提示用户键入某一货币数量(以分为单位),该程序应计算出如何用最少量的1元,50分,10分和1分硬币得到该数目。如195分最少可以用一个1元硬币,1个50分...