理解Java字符串的==

首先,==比較的是字符串的地址。

我們知道存在String常量池,那麼什麼時候會將字符串放入常量池呢?

如下,3個地方賦值String。

public class AA {
	String s0 = new String("aaa");

	void fun() {
		String ss = new String("11");
	}

	public static void main(String[] args) {
		String s = "A" + "B";
	}
}

 如下查看對應class文件可知,直接引號賦值和new賦值都會放入常量池,而且String s = "A" + "B";這個語句在編譯器優化後常量池只有AB。即字符串常量相加在編譯器就會直接產生相加後的常量。注意只有都是字符串常量相加纔會放入常量池。如果是String s="A"+new String("B");那麼常量池中有A和B,卻沒有AB。

Constant pool:
   #1 = Methodref          #9.#21         // java/lang/Object."<init>":()V
   #2 = Class              #22            // java/lang/String
   #3 = String             #23            // aaa
   #4 = Methodref          #2.#24         // java/lang/String."<init>":(Ljava/lang/String;)V
   #5 = Fieldref           #8.#25         // AA.s0:Ljava/lang/String;
   #6 = String             #26            // 11
   #7 = String             #27            // AB
   #8 = Class              #28            // AA
   #9 = Class              #29            // java/lang/Object
  #10 = Utf8               s0
  #11 = Utf8               Ljava/lang/String;
  #12 = Utf8               <init>
  #13 = Utf8               ()V
  #14 = Utf8               Code
  #15 = Utf8               LineNumberTable
  #16 = Utf8               fun
  #17 = Utf8               main
  #18 = Utf8               ([Ljava/lang/String;)V
  #19 = Utf8               SourceFile
  #20 = Utf8               AA.java
  #21 = NameAndType        #12:#13        // "<init>":()V
  #22 = Utf8               java/lang/String
  #23 = Utf8               aaa
  #24 = NameAndType        #12:#30        // "<init>":(Ljava/lang/String;)V
  #25 = NameAndType        #10:#11        // s0:Ljava/lang/String;
  #26 = Utf8               11
  #27 = Utf8               AB
  #28 = Utf8               AA
  #29 = Utf8               java/lang/Object
  #30 = Utf8               (Ljava/lang/String;)V

 

那麼下面這個就很好理解了:

	String s1="aa"+"bb";
	String s2="aabb";
	System.out.println(s1==s2);//true

	String s1="aa"+new String("bb");
	String s2="aabb";
	System.out.println(s1==s2);//false

 

String中有一個方法intern:根據方法介紹,如果常量池中沒有則將其放入常量池,如果有了則返回常量池相應引用

注意以下最後2個例子:

	//此時創建了2個對象,一個堆內,一個常量池中
        String s1=new String("1");
	String s2="1";
	System.out.println(s1==s2);//false

        //s1仍然指向堆中對象,s2指向常量池中字符串
        String s1=new String("1");
        s1.intern();//這句相當於無用,因爲常量池已經有了
	String s2="1";
	System.out.println(s1==s2);//false

        //intern返回常量池中字符串引用,故相等
	String s1 = new String("1").intern();
	String s2 = "1";
	System.out.println(s1 == s2);//true

        //參考下面
	String s1 = new String("1")+new String("2");
	String s2 = "12";
	System.out.println(s1 == s2);//false

        //此處jdk1.6及之前爲false,jdk1.7開始字符串常量池處於堆內而不是方法區了。
        //以jdk1.7爲例,常量池中有1和2,但是沒有12。在此情況下調用intern,常量池將存儲指向堆內字符串12的引用而非字符串12,即s2其實也是指向堆內12的。
	String s1 = new String("1")+new String("2");
        s1.intern();
	String s2 = "12";
	System.out.println(s1 == s2);//true by jdk1.7+

        //雖然也調用了intern,但是s2賦值時常量池沒有12,所以將字符串12放入常量池並返回引用。
        //再調用intern相當於無效(常量池已有字符串)
	String s1 = new String("1")+new String("2");
	String s2 = "12";
        s1.intern();
	System.out.println(s1 == s2);//false

final也會起到作用:變量與常量的區別。

		final String a = "hello";
		String b = "hello";
		String c = a + "a";
		String d = b + "a";
		String e = "helloa";
		System.out.println((d == e));// false
		System.out.println((c == e));// true

PS:String s=new String("1")+new String("2");這個語句創建了多少個對象?(個人認爲6個,具體請自己javap -v xxx.class查看)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章