一:String
直接赋值和使用new的区别
String str = new String();
此时JVM
Demo_01_String
//直接赋值
String str1 = "hello";
String str2 = "hello";
String str3 = "world";
System.out.println("string==:"+(str1 == str2));//true:二者都指向常量池中同一对象,其地址值相同
System.out.println("string==:"+(str2 == str3));//false
System.out.println("string.equals:"+str1.equals(str2));//true
System.out.println("str1地址:"+str1.hashCode()); //99162322
System.out.println("str2地址:"+str2.hashCode()); //99162322
System.out.println("str3地址:"+str3.hashCode()); //113318802
// new String
String str4 = new String("hello");
String str5 = new String("hello");
String str6 = new String("world");
System.out.println("string==:"+(str1 == str4));//false:存放的地址不同
System.out.println("string==:"+(str4 == str5));//false:比较两个包装类的引用是否指向同一个对象,即在堆中的地址是否相同
System.out.println("string.equals:"+str1.equals(str4));//true 比较引用类型的值是否相等
System.out.println("string.equals:"+str4.equals(str5));//true
System.out.println("str4地址:"+str4.hashCode()); //99162322
System.out.println("str5地址:"+str5.hashCode()); //99162322
System.out.println("str6地址:"+str6.hashCode()); //113318802
//字符串相加
String strConst = str2 + str3;//是先加,然后在常量池找
String strNew = str5 + str6;//先开空间,再拼接
System.out.println(strConst.hashCode());
System.out.println(strNew.hashCode());
System.out.println("字符串相加后比较:"+(strConst == strNew)); //
System.out.println("字符串相加后比较:"+strConst.equals(strNew));
Demo_02_StringBuffer
StringBuffer sbf1 = new StringBuffer("hello");
StringBuffer sbf2 = new StringBuffer("hello");
StringBuffer sbf3 = new StringBuffer("world");
System.out.println("stringBuffer==:"+(sbf1 == sbf2)); //false
System.out.println("stringBuffer.equals:"+sbf1.equals(sbf2)); //false
System.out.println("stringBuffer.equals:"+sbf2.append(sbf3)); //拼接
Demo_03_StringBuilder
StringBuilder sbu1 = new StringBuilder("hello");
StringBuilder sbu2 = new StringBuilder("hello");
StringBuilder sbu3 = new StringBuilder("world");
System.out.println("stringBuilder==:"+(sbu1 == sbu2)); //false
System.out.println("stringBuilder.equals:"+sbu1.equals(sbu2)) //false
System.out.println("stringBuilder.equals:"+sbu2.append(sbu3));
- 由于String变量实际上是对一个String对象的引用(指向常量池),所以两个通过new生成的String变量永远是不相等的(因为new生成的是两个对象,其(在堆中的)内存地址不同)。
- String是final类,其值是不可变的,看以下板栗,只是改变了赋值地址;
// 1. 重新赋值
String str1 = "hello";
System.out.println("str1原本地址:"+str1.hashCode()); //99162322
str1 = "java";
System.out.println("str1改变后的地址:"+str1.hashCode()); //3254818
重新赋值后str1指向新地址,但旧地址中保存的"world"依旧存在,但已经不再是str1所指向的,str1已经指向了其它地址。
所有对String类型进行改变的时候都会重新生成一个新的String对象,如果字符串的内容经常改变,而且不考虑多线程的话,建议使用StringBuilder
// 2. 字符串拼接后地址有无改变?
String strConst = str2 + str3;//是先加,然后在常量池找
String strNew = str5 + str6;//先开空间,再拼接
System.out.println("字符串拼接后的地址:"+strConst.hashCode()); //变成-1524582912
System.out.println("字符串拼接后的地址:"+strNew.hashCode()); //变成-1524582912
System.out.println("sbf3原本地址:"+sbf3.hashCode()); //27134973
System.out.println("sbf3拼接后:"+sbf2.append(sbf3));
System.out.println("sbf3拼接后的地址:"+sbf3.hashCode()); //还是sbf3的地址27134973
查看源码可知String重写了equals()方法,但StringBuffer和StringBuilder没有
看JDK怎么说
StringBuffer
- 是线程安全的可变字符序列,可将字符串缓冲区安全地用于多个线程,可以在必要时对这些方法进行同步;
- 主要操作是 append 和 insert 方法;
- 没有重写equals方法
StringBuilder
- 此类提供一个与 StringBuffer 兼容的 API,但不保证同步;
- 该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候,这样比buffer快
- 主要操作和buffer一样
- 没有重写equals方法
总结
- String = 操作少量的数据
- StringBuilder = 单线程操作字符串缓冲区 下操作大量数据;线程非安全的
- StringBuffer = 多线程操作字符串缓冲区 下操作大量数据;线程安全的