谈谈String

一、String类

    我们都知道String是一个不可变对象,用final修饰,这说明它不能被继承和修改

    这是Stirng类的部分源码,可以看到,它用final声明了一个char类型的数组,实际上,它就是用来保存字符串的,这也就是为什么字符串的值是不能被改变的原因,再看看下面String类中两个相关方法的代码

 

      

可以看到,对字符串的操作最后都是生成一个新的字符串对象,原先的字符串对象并没有被改变,所有对字符串的更改操作都会产生一个新的字符串对象

二、字符串常量池

在进一步了解String之前,我们先来说说字符串常量池
字符串是我们经常使用的,如果每次修改一个字符串就产生一个新对象的话,这无疑是很耗资源的。JVM为了对这种情况进行优化,使用了字符串常量池。

 1、直接创建

 String str1 = “helloworld”
 String str2 = “helloworld”
 当我们以字面量的形式创建字符串str1时,JVM会先从字符串常量池中查找是否存在"helloworld"这个对象,这里没有,所以会在池中创建一个helloworld对象,然后将该对象的引用返回给str1,在创建str2时,同样会去常量池中查找是否有hellloworld对象,因为前面str1已经创建了一个helloworld对象,所以此时会直接返回该对象的引用,此时的str1和str2是相等的

 2、以new的形式创建

 String str3 = new String("helloworld")
 当我们以new的形式创建str3时,JVM会从池中查找有没有helloworld,这里因为在创建str1时已经创建了helloworld对象,所以不会在池中创建对象了,如果池中没有helloworld对象的话,在池中创建一个helloworld对象,然后拷贝一份到堆中,并将堆中的引用返回。此时的str3与str1是不同的对象。要注意使用new产生的字符串的引用是堆中的引用,而不是池中的引用。
 由此可知,使用new创建字符串对象的时候,实际上产生了两个对象
---------在继续了解更多关于与字符串与常量池之间关系的前,先来说说“+”连接符
 我们都知道“+”在字符串中是用来拼接多个字符串的
 String s1 = "java"
 String s2 = "php"
 String s3 = "java" + "php"
 String s4 = s1 + s2
 s3和s4都是用“+”拼接而成的,s3中的“java”和“php”都是字符常量,在编译时就已经确定了,实际上s3就相当于直接写s3 = "javaphp",因为它是两个字符串常量拼接而成的,JVM会在编译期进行优化;s4是由两个字符引用拼接而成的,因为s1和s2是字符引用,在编译时无法确定具体的值,必须在运行时才能确定;当“+”拼接多个字符引用的时候,实际上底层是以第一个“+”左边的第一个引用来创建一个StringBuilder对象,然后再通过append()方法来拼接其他字符引用,最后再通过toString()方法返回一个新的String对象,所以这里的s4可以简单的看作是s4 = new StringBuilder(s1).append(s2).toString()

 3、用 “+”连接常量

 String str4 = "hello" + "world"
 str4是由两个字符常量"hello"、"world"连接而成的,它们在编译期就已经是确定的了,因为str4由字符串常量组成,所以它本身也是一个字符串常量,就相当于str4 = "helloworld",也会在池中查找是否存在对应的对象,此时的str4与str1是一样的

 4、用“+”连接字符引用

 String str5 = "hello"
 String str6 = "world"
 String str7 = str5 + str6
 str5和str6都是编译时就已经确定的了,而str7是有str5和str6两个字符引用连接而成的,上面已经说了对于“+”拼接多个字符引用的情况,这里也是一样的道理,最后产生的str7是一个新的String对象,所以str7与str1是不同的对象

 5、final修饰的String

 final String str8 = "fin"
 final String str9 = Person.name
 String str10 = “a” + str8
 String str11 = “a” + str9
对于final修饰的String,如果修饰的是一个普通值,则在编译时就已经被解析为常量了,str8就是可以看成是一个常量,str10就可以直接看成是afin,而str9是通过对象(方法也不可以)来赋值的,这在编译时是无法确定的,只能在运行时才能确定,不能看成常量

三、小结

 1、String是不可变的,有关String的修改操作全部都会产生一个新的String对象,原本的String对象不变,如果没被使用就等待被GC回收
 2、用字面量的方式创建String对象时,会先从字符串常量池中查找是否存在相同字符串的对象引用,如果有就返回引用,没有 就创建对象后再返回对象的引用
 3、用new的方式创建String对象时,会先从字符串常量池中查找是否存在相同字符串的对象引用,如果没有就创建,如果有就拷贝一份到堆中,返回堆中对象的引用
 4、使用String类的intern()方法可以往字符串常量池中添加对象:调用intern的字符串,会去字符串常量池中查找是否有与自己相等的字符串对象,如果有就返回该对象,没有就把自己添加到池中,并返回对应的引用
 5、使用“+”来拼接字符串引用,需要在运行时才能够确定引用的字符串的值,底层是使用StringBuilder来实现的,最后获得的是一个新的对象


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值