文章目录
一:String 类构成
final char[] ch;//"hello"
二:String类掌握的方法
- toCharArray() 转数组
- equals方法进行比较
- char c = charAt(int index);
- 字符串长度 = str.length();
- 分割函数:split(); “i am a student” “student a am i”
- subString();子串,compareTo()比较函数 ,toUpperCase()转大写
- String.valueOf(10); 将整型10转为字符串类型
三:"+"连接符
1、"+"连接符的实现原理
常量 + 常量: "1"+"2"
编译器 优化 -> "12"
变量+常量 String str="1"; str+"2"; ->"12"
实际代码实现:
StringBuilder s = new StringBuilder()
s.append("1");
s.append("2");
String str = s.toString();
2、"+"连接符的效率
使用“+”连接符时,JVM会隐式创建StringBuilder对象,这种方式在大部分情况下并不会造成效率的损失,不过在进行大量循环拼接字符串时则需要注意。
String s = "abc";
for (int i=0; i<10000; i++) {
s += "abc";
}
/**
* 反编译后
*/
String s = "abc";
for(int i = 0; i < 1000; i++) {
s = (new StringBuilder()).append(s).append("abc").toString();
}
这样由于大量StringBuilder创建在堆内存中,肯定会造成效率的损失,所以在这种情况下建议在循环体外创建一个StringBuilder对象调用append()方法手动拼接(如上面例子如果使用手动拼接运行时间将缩小到1/200左右)
/**
* 循环中使用StringBuilder代替“+”连接符
*/
StringBuilder sb = new StringBuilder("abc");
for (int i = 0; i < 1000; i++) {
sb.append("abc");
}
sb.toString();
综上,“+”连接符对于直接相加的字符串常量效率很高,因为在编译期间便确定了它的值,也就是说形如"I"+“love”+“java”; 的字符串相加,在编译期间便被优化成了"Ilovejava"。对于间接相加(即包含字符串引用,且编译期无法确定值的),形如s1+s2+s3; 效率要比直接相加低,因为在编译器不会对引用变量进行优化。
四:字符串常量池
每当创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于String字符串的不可变性,常量池中一定不存在两个相同的字符串。
1、内存区域
在JDK1.6及之前版本,字符串常量池是在方法区中的;在JDK1.6版本之后,字符串常量池被移到了Java堆中。
2、存放内容
String s1 = "AB";
String s2 = "AB";
String s3 = new String("AB");
System.out.println(s1 == s2);//ture
System.out.println(s1 == s3);//false
由于常量池中不存在两个相同的对象,所以s1和s2都是指向JVM字符串常量池中的"AB"对象。new关键字一定会产生一个对象,并且这个对象存储在堆中。所以String s3 = new String(“AB”);产生了两个对象:保存在栈中的s3和保存堆中的String对象。
当执行String s1 = "AB"时,JVM首先会去字符串常量池中检查是否存在"AB"对象,如果不存在,则在字符串常量池中创建"AB"对象,并将"AB"对象的地址返回给s1;如果存在,则不创建任何对象,直接将字符串常量池中"AB"对象的地址返回给s1。
五:intern方法
String对象的intern方法会得到字符串对象在常量池中对应的引用,如果常量池中没有对应的字符串,则该字符串将被添加到常量池中,然后返回常量池中字符串的引用;
六:String、StringBuilder和StringBuffer
相同点:都可以对字符串进行操作
不同点:
- 多线程环境:
线程安全:StringBuffer
不安全:String StringBuilder - 效率问题分析(不考虑多线程环境的情况下):
常量+常量→String
变量+常量 → String StringBuilder
1、三者主要区别
- String是不可变字符序列,StringBuilder和StringBuffer是可变字符序列。
- 执行速度StringBuilder > StringBuffer > String。
- StringBuilder是非线程安全的,StringBuffer是线程安全的。
七: "=="和"equals()"的区别
“==”用于比较基本数据类型的值是否相等或者引用数据类型的引用是否相等(严格意义上说是同一个对象,因此肯定相等);“.equals()”方法用于比较引用对象是否相等,该方法继承自object,覆写该方法完成自定义的比较规则。
八:练习
public static void main(String[] args) {
String s1 = "AB";
String s2 = new String("AB");
String s3 = "A";
String s4 = "B";
String s5 = "A" + "B";
String s6 = s3 + s4;
System.out.println(s1 == s2);//false
System.out.println(s1 == s5);//ture
System.out.println(s1 == s6);//false
System.out.println(s1 == s6.intern());//ture
System.out.println(s2 == s2.intern());//false
}
解析:真正理解此题目需要清楚以下三点
- 直接使用双引号声明出来的String对象会直接存储在常量池中;
- String对象的intern方法会得到字符串对象在常量池中对应的引用,如果常量池中没有对应的字符串,则该字符串将被添加到常量池中,然后返回常量池中字符串的引用;
- 字符串的+操作其本质是创建了StringBuilder对象进行append操作,然后将拼接后的StringBuilder对象用toString方法处理成String对象,这一点可以用javap -c命令获得class文件对应的JVM字节码指令就可以看出来。
参考文献:
https://blog.csdn.net/ifwinds/article/details/80849184