A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 月落 初级黑马   /  2019-3-22 15:10  /  1701 人查看  /  2 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文


从内存分配情况来解析String对象的特性。
String类的Java介绍
打开String的源码,类注释中有这么一段话:Strings are constant; their values cannot be changed after they are
created. String buffers support mutable strings.Because String objects are immutable they can be shared
这里很明确的说明了String的特点:String是值不可变(immutable)的常量
String类的两个成员变量

private final char value[];
private final int count;
从代码上我们可以直观的看出来,String的本质其实是字符数组。
String类的拼接
前面提到过String类的值是不可变的,但是我们在使用String类的方法中,有一个叫concat的方法,它的效果好像
是在做字符串的改变,我们可以看看这个方法内部到底是如何实现的呢?
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
将原来value中的字符copy到buf中来,再把需要concat的字符串值也copy到buf中来,这样子,buf中就包含了
concat之后的字符串值。下面就是问题的关键了,如果value不是final的,直接让value指向buf,然后返回this,
则大功告成,没有必要返回一个新的String对象。由于value是final型的,所以无法指向新定义的大容量数组buf,
那怎么办呢?“return new String(0, count + otherLen, buf);”,这是String类concat实现方法的最后一条语句,重
新new一个String对象返回。

常量池
常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、
方法、接口等中的常量,也包括字符串常量。常量池还具备动态性,运行期间可以将新的常量放入池中。虚拟机为
每个被装载的类型维护一个常量池,池中为该类型所用常量的一个有序集合,包括直接常量(string、integer和
float常量)和对其他类型、字段和方法的符号引用

String的定义方式
直接定义,如:String s1 = "myString";
串联生成,如:String s2 = "my" + "String";
使用关键字new,如:String s3 = new String("myString");
直接定义
第一种方式通过关键字new定义过程:在程序编译期,编译程序先去字符串常量池 检查,是否存
在“myString”,如果不存在,则在常量池中开辟一个内存空间存放“myString”;
  
串联生成
两个常量字符串相加,Java中有常量优化机制,会进行预编译,先在常量池中查找有没有myString这样的字
符串常量,如果有那么就直接引用了
  
使用new关键字 new关键字一定会产生一个对象String这个对象是存储在堆中。保存在栈中的s3和保存堆中
myString。但是在Java中根本就不存在两个完全一模一样的字符串对象。故堆中的myString应该是引用字符
串常量池中myString。

  
字符串变量相加
String s1 = "a";
String s2 = "b";
String s3 = "c";
String s4 = s1 + s2 + s3;

这里因为s4是变量s1,s2,s3相加得出来的结果,常量优化机制在这里无法起作用,在程序运行时,这种拼接的操
作,java会创建一个StringBuilder,来帮助完成字符串的拼接。实际上等价于:
StringBuilder temp = new StringBuilder();
temp.append(a).append(b).append(c);
String s = temp.toString();

总结
如果是字符串常量拼接,不会影响性能,因为有常量优化的存在
如果在字符串拼接的过程中有变量参加,一定要注意使用StringBuilder进行手动的拼接字符串来提高性能,
否则会有频繁的JVM自动创建StringBuilder,造成内存的浪费




2 个回复

正序浏览
只想说现在还没有理解
回复 使用道具 举报
请加个标题吧;代码部分可以使用编辑器中的插入代码功能,这样笔记排版更美观,阅读量会更多。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马