Java字符串创建与存储的机制

在Java语言中,字符串起着非常重要的作用,字符串的声明与初始化主要有如下两种情况:

1)对于语句:

String s1 = new String("abc");
String s2 = new String("abc");

存在两个引用对象s1和s2,两个内容相同的字符串对象“abc”,它们在内存中的地址是不同的。

只要用到new,总会生成新的对象。

2)对于语句:

String s1 = "abc";
String s2 = "abc";

在JVM中存在着一个字符串池,其中保存着很多String对象,并且可以被共享使用,s1、s2引用的是同一个常量池中的对象。由于String的实现采用了Flyweight的设计模式,当创建一个字符串常量时,例如:

String s = "abc";

会首先在字符串常量池中查找是否已经有相同的字符串被定义,其判断依据是String类equals(Object obj)方法的返回值。若已经定义,则直接获取对其的引用,此时不再需要创建新的对象;若没有定义,则首先创建这个对象,然后把它加入到字符串常量池,再将它的引用返回。


由于String是不可变类,一旦创建好了就不能被修改,因此String对象可以被共享而且不会导致程序的混乱。

具体而言:

String s = "abc";				//把"abc"放到常量区中,在编译时产生


String s = "ab"+"c";			//把"ab"+"c"转换为字符串常量"abc"放到常量区中

String s = new String("abc");	//在运行时把"abc"放到堆里面

例如:

String s1 = "abc";				//在常量区里面存放了一个"abc"字符串对象
String s2 = "abc";				//s2引用常量区中的对象,因此不会创建新的对象
String s3 = new String("abc");	//在堆中创建新的对象
String s4 = new String("abc");	//在堆中又创建一个新的对象

为了便于理解,可以把:

String s = new String("abc");

语句的执行认为的分解成两个过程:

1、新建对象的过程,即new String("abc");

2、赋值过程,即String s = 。

由于第二个过程只是定义了一个名为s的String类型的变量,将一个String类型对象的引用赋值给s,因此在这个过程中不会创建新的对象。第一个过程中new String("abc")会调用String类的构造函数:

public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }

在调用这个构造函数时,传入了一个字符串常量,因此语句new String("abc")也就等价于"abc"和new String()两个操作了。若在常量池中不存在"abc",则会创建一个字符串常量"abc",并将其添加到字符串池中;若存在,则不创建,然后new String()会在堆中创建一个新的对象,所以s3与s4指向的是堆中不同的String对象,地址自然不同了,如下图所示:


引申:

对于String类型的变量s,赋值语句s=null与s=“”是否相同?

对于赋值语句s=null,其中s是一个字符串类型的引用,它不指向任何一个字符串。而赋值语句s=“”中的s是一个字符串类型的引用,它指向另外一个字符串(这个字符串的值为“”,即空字符串),因此,这二者是不同的。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值