复习字符串创建方式
字符串的3+1种构造方法
- public String();创建一个空白字符串, 不含有任何内容
- public String(char[] array);根据字符数组的内容,来创建对应的字符串
- public String(byte[] array);根据字节数组的内筒,来创建对应的字符串
String str1 = new String();
char[] ch1 = new char[]{'3', '%', d"};
String str2 = new String(ch1);
byte[] by1 = new byte[2];
by1[0] = 23;
by1[1] = 12;
String str3 = new String(by1);
1 种直接创建 String str = "Hello";
注意:直接写上双引号,就是字符串对象。只要是字符串一定是对象
只有1种直接创建的字符串在堆中的字符串常量池中,其他3种new 创建的都在堆
拼接,截取操作后得到的字符串是否在常量池。(判断标准)
- 常量池的字符串内容相同就是一个对象,用==比较是不是一个字符串对象
- 用concat(String)拼接字符串;用+拼接字符串;
- 从其他字符串中截取substring(2种);
- 用replace替换字符串中字符得到返回值。
- 用split分割得到字符串数组。
- 假设得到的字符内容都是abcabc,检查最终得到的字符串是否在常量池中
public class MainTest {
public static void main(String[] args) {
//以下所有比较的字符串内容相同
String str = "abcabc";
String strCopy = "abcabc";
String str1 = "ab".concat("cabc");
String str2 = "a" + "bca" + "bc";
String str22 = "bca";
String str3 = "a" + str22 +"bc";
String str4 = "aecaec".replace("e","b");
String[] strArr1 = "abcabceartdeagfdseae".split("ea");
String str5= strArr1[0];
System.out.println(str == str1);//false//方法拼接的str1在堆
System.out.println(str == str2);//true//字符串常量+拼接的字符串str2,在常量池
System.out.println(str == "a" + "bca" + "bc");//true//字符串常量+拼接的匿名字符串结果,也在常量池
System.out.println(str == str3);//false//其中有str22字符串引用拼接,str3在堆
System.out.println(str == str4);//false//方法替换得到的str4在堆
System.out.println(str == str5);//false//方法截取得到的str5在堆
System.out.println(str == strCopy);//true//直接创建的在常量池
String str11 = "aaa";
String str88 = "aaa";
System.out.println("str8:" + str11 == "str8:aaa");//false//+优先级高,最终笔试双方为 "str8:aaa" == "str8:aaa"但"str8:" + str1得到的字符串在堆,因为str8是字符串引用,“+”拼接在运行期间
System.out.println(("str8:" + str11) == "str8:aaa");//false//同上
System.out.println("str8:" + (str11 == "aaa"));//str8:true//直接创建在常量池
}
}
重点对比str2、str3
都是用+拼接,怎么一个在常量池,一个不在?
注意区分字符串常量和字符串引用,即一个直接创建且匿名一个有名字
- str2在常量池因为:
字符串常量拼接在编译期间就已经完成,“+”号操作时处于编译时期。编译完后的“abcabc”放入常量池 - str3在堆因为:
字符串引用的拼接在运行时执行,“+”号操作时处于运行时期。执行完语句后创建一个新的字符串引用str3在堆来接收"a" + str22 +"bc"的结果。其中“a” ,str22和“bc”都在常量池,因为都是直接创建的,只有str3这个用引用有str22参与,“+”号拼接的在堆。
总结:
- 对于String,属于引用类型,而
==
比较引用类型,必须得是同一个对象才true。
在常量池的字符串只要内容一样,就是同一个对象 - 而使用空参,字符数组,字节数组这3种方式创建的String对象(还有使用字符串常用方法拼接、截取、替换得到的String)(和+拼接字符串引用得到的String对象), 以上字符串, 内容相同也不是同一个对象,因为不在常量池中保存。 在堆中保存
- 直接创建的字符串,和+ 拼接字符串常量得到的String对象,都保存在堆中的字符串常量池中保存。特点:只要内容相同,就是同一个对象。即内容相同用==比较为true
- 对于
sout("str8:" + str1 == "str8:aaa")
因为 + 优先于==
实际比较的是 “str8:” + str1(即str8:aaa)和 后续的字符串比较,明明内容相同为啥false呢,因为“字符串引用”经过+
拼接得到的字符串也不在常量池。不是一个对象
用equals比较就相同了,因为equals比较File,Data,String和包装类是比较的内容,而不是地址,所以不要求必须是同一个对象才true。因为这几个类重写了equals方法