沙漠中的鱼

欲上天堂,先下地狱
posts - 0, comments - 56, trackbacks - 0, articles - 119
  BlogJava :: 首页 ::  :: 联系 :: 聚合  :: 管理

String对象是不可变的

Scanner扫描字符串对象。

备注:

在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.使用重载的字符串连接操作符+创建.

面试题:

String s1 = new String("s1") ;
String s2
= new String("s1") ;
上面创建了几个String对象
?
答案:3个 ,编译期Constant Pool中创建1个,运行期heap中创建2个.



只有注册用户登录后才能发表评论。


网站导航: