前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >5Java学习笔记之数据结构——字符串String

5Java学习笔记之数据结构——字符串String

作者头像
天涯泪小武
发布2019-01-17 11:08:05
3740
发布2019-01-17 11:08:05
举报
文章被收录于专栏:SpringCloud专栏SpringCloud专栏

字符串这个非常非常常用的数据结构,平时用的最多,但它到底是怎么工作的,可能没多少人去关心过。下面就来谈谈这个String到底有什么特殊的。

String s1 = "abc";

String s2 = "abc";

String s3 = "ab" + "c";

String s4 = new String("abc");

判断上面s1,s2,s3,s4是否相等,用==

答案是:s1==s2==s3!=s4。

在java里判断==的条件是引用地址相同,可以理解为指向这块内存的指针是相等的,当s1,s2,s3都相等时说明等号后面的"abc"只有一份,它们只是指向同一个内存块而已。

再看一个普通的class对象。有个Person类,有个int age属性。

Person p = new Person();

p.setAge(10);

给一个对象p的age赋值为10.此时如果把p作为参数传给别的方法,譬如有个

void change(Person p) {p.setAge(5);}

当把p传给change方法后,再查看原来的p的age,发现已经被修改成5了。说明通过new Person()得到的p在内存中只有1份,当在任何地方被修改后,p的属性就被修改了。

刚才说了s1,s2,s3它们都指向了同一块内存地址,"abc"只有唯一的一份,那是否可以猜测s2+"d"后,s1和s3也会随之改变呢。

答案是no。只有s2自己变成了"abcd",s1和s3不会有任何变化,因为系统又开辟了一块新的内容来装"abcd"。

那假如是下面的情况呢:

String s4 = new String("abc");

String s5 = s4;

s5 += "d";

求s4?

答案是s4依旧没有变化。看起来貌似和Person不太一样是吧。String就是比较特殊。

特殊在哪里呢?

1.String存放的地方和普通的类不一样

2.String不可改变,一旦一个String对象定义完毕,没有任何修改它的地方,它的所有属性都不可修改。修改后的那就是另外一个String了

我们主要关心的有栈,堆,和String常量存放的地方——方法区。(http://zangxt.iteye.com/blog/472236)

栈里主要存放的基本数据类型(int,double等),和对象的引用(如Person p = new Person()中的p),有时递归过深时发生栈溢出,说的就是这个,因为存放了调用关系层次过多导致栈溢出。

堆里是供线程共享的内存区域,存放的是对象实例,譬如Person被new后,里面的所有属性都在堆里开辟了内存来存放,这一块也是gc需要频繁关注的地方。

String有一块常量区(方法区),用来存放String。

当执行String s1 = "abc";时,系统便在这块常量区里,开辟了内存保存“abc”,并将指向这块内存的指针s1返回给调用者。以后只要常量区里还有"abc",再去定义String s2 = "abc",系统就不会再次开辟内存,而是直接将地址返回给s2.所以s1==s2。

所以当你定义String s2 = "abc"时,系统可能创建一个对象或者不创建对象,如果已经有了,那就直接返回地址,如果没有,那就创建。

但是String s4 = new String("abc")时,系统至少创建一个对象,用了new关键字,也就是至少会在栈里创建一个s4,然后再去常量区判断“abc”是否存在,不存在时new String这一步就会创建两个对象。可以看到,这样会额外耗费一个栈里的空间。所以平时,多用直接=的方式来创建String。

所以s4!=s2.

然后再看另外一个问题:

String a = "abc";

String b = "ab";

String c = b + "c";

问a==c吗?

答案是不等。因为a和b都是字符串常量,在编译期就被确定了,内存地址已被确定。

而c里面有个b是个变量,b是存放在栈里的一个引用而已,所以c不会在编译期确定,只会在运行时确定。那么a!=c。

而且,上面说过,String类是final的,里面也没有任何修改属性的方法,String是不可变的。当执行b + "c"时,底层是用StringBuilder类的append方法进行连接字符串的,连接完毕再toString返回引用地址的。

那为什么"ab" + "c" 却 == "abc"呢?

这是Jvm在编译期做的优化。

String s = "ab" + "c";这种只有常量的,会在编译期被合并,等同于String s = "abc"。然后将"abc"作为常量存放在常量区。或者这样的,也是==的

"a" + 1 + "b" == "a1b"

假如是这样:

int x = 1;

String s = "a" + x + "b"; 

这样就不等了。

在编译期内,只会优化合并所有变量之前的常量。"a" + "1" + x + "b",像这种就相当于先合并"a1",然后再new一个StringBuilder再去append后面的几个值。

参考:http://www.cnblogs.com/ITtangtang/p/3976820.html

总结一下,直接指定的String,如String s = "abc",对象"abc"是存放在常量池中的,s在栈里。

String s = new String("abc"),对于通过 new 产生一个字符串时,会先去常量池中查找是否已经有了 ”abc” 对象,如果没有则在常量池中创建一个此字符串对象,然后堆中再创建一个常量池中此 ”abc” 对象的拷贝对象。

不管存放在哪,String都是不可变的,用+号连接时,走的是StringBuiler创建了新对象.

参考:http://blog.csdn.net/u014082714/article/details/50087563

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年03月29日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档