前言
String這種東西天天都在用,但是還真的沒有專門研究過,只是之前簡單看過一些介紹。今天專門研究一下,加深一些印象,這些基礎知識都是JAVA程序員(非碼農)必須應該具備的硬實力。
實驗代碼
package com.java.example.demo.string;
/**
* 練習String知識點
*/
public class StringDemo {
public static void main(String[] args) {
String str1 = "zhaoxiaoluo";
String str2 = "zhaoxiaoluo";
String str3 = "zhao" + "xiaoluo";
String temp = "xiaoluo";
String str4 = "zhao" + temp;
String str5 = new String("zhaoxiaoluo");
String str6 = new String("zhaoxiaoluo");
String str7 = str6.intern();
// == 比較是否是同一個引用
System.out.println("str1 str2:" + (str1 == str2));
System.out.println("str1 str3:" + (str1 == str3));
System.out.println("str1 str4:" + (str1 == str4));
System.out.println("str1 str5:" + (str1 == str5));
System.out.println("str1 str7:" + (str1 == str7));
System.out.println("str5 str6:" + (str5 == str6));
System.out.println("str5 str7:" + (str5 == str7));
//使用equals比較值
System.out.println("下面是equals:");
System.out.println(str1.equals(str2));
System.out.println(str1.equals(str3));
System.out.println(str1.equals(str4));
System.out.println(str1.equals(str5));
System.out.println(str1.equals(str7));
System.out.println(str5.equals(str6));
System.out.println(str5.equals(str7));
}
}
執行結果
str1 str2:true
str1 str3:true
str1 str4:false
str1 str5:false
str1 str7:true
str5 str6:false
str5 str7:false
下面是equals:
true
true
true
true
true
true
true
理論知識補充
字符串的分配,和其他對象分配一樣會耗費大量時間和空間代價。JVM爲了提升性能和減少消耗,在實例化字符串常量時進行了一些優化。由於字符串的不可變性,爲了減少在JVM中創建字符串的數量,Java維護了一個字符串常量池。每當有字符串常量被創建時,JVM會首先檢查字符串常量池中是否已存在該字符串。若存在,返回該對象的引用。若不存在,實例化該字符串放在常量池中。
Java的堆內存是專門用來存放對象的,若使用new String這種形式,會生成一個新的String對象,強制存放在了堆內存中,就不會去和常量池作比較,所以引用地址是不一致的。
intern()方法是強制返回常量池中的對象引用,若常量池中已存在,則返回對應常量池中的引用,若不存在,實例化後放入常量池,返回該引用。
解析版代碼
package com.java.example.demo.string;
/**
* 練習String知識點(解析版)
*/
public class StringDemo2 {
public static void main(String[] args) {
//1、去常量池中查詢,沒有“zhaoxiaoluo”,實例化並放入常量池
String str1 = "zhaoxiaoluo";
//2、去常量池中查詢,有“zhaoxiaoluo”,直接返回該引用,所以此處和str1指向的是同一個常量池地址
String str2 = "zhaoxiaoluo";
//3、編譯期會將 兩個常量拼接在一起,然後去常量池中查詢“zhaoxiaoluo”,同str2
String str3 = "zhao" + "xiaoluo";
//4、由於涉及了變量,運行時纔會拼接在一起(非編譯期),其內部實現是先new一個StringBuild,
//stringBuild.append("zhao").append(temp).toString();所以是返回了一個新的對象
String temp = "xiaoluo";
String str4 = "zhao" + temp;
//5、使用 new String創建了一個 String對象,所以強制放在了堆內存中(堆內存放對象實例),
// 沒有和常量池比對,也沒有放在常量池,所以和str1不是一個地址
String str5 = new String("zhaoxiaoluo");
//6、同str5,會存放在堆內存中,堆內存中每次都是新增對象(無論值是否相等)
String str6 = new String("zhaoxiaoluo");
//7、intern()方法的作用就是,返回一個字符串常量池中的引用,
// 若常量池中存在該字符串,返回引用,否則,在常量池中新增該字符串
String str7 = str6.intern();
// == 比較是否是同一個引用
System.out.println("str1 str2:" + (str1 == str2));
System.out.println("str1 str3:" + (str1 == str3));
System.out.println("str1 str4:" + (str1 == str4));
System.out.println("str1 str5:" + (str1 == str5));
System.out.println("str1 str7:" + (str1 == str7));
System.out.println("str5 str6:" + (str5 == str6));
System.out.println("str5 str7:" + (str5 == str7));
//如果用equals比較值的話,因爲所有的值都是“zhaoxiaoluo”,所以都是相等的
System.out.println("下面是equals:");
System.out.println(str1.equals(str2));
System.out.println(str1.equals(str3));
System.out.println(str1.equals(str4));
System.out.println(str1.equals(str5));
System.out.println(str1.equals(str7));
System.out.println(str5.equals(str6));
System.out.println(str5.equals(str7));
}
}