虛擬機 常量池

之前將"虛擬機必須爲每個被裝載的類型維護一個常量池"這句話理解成了不同的類型的類聲明中如果有相同類型的對象域,即使對象域持有的字面量一樣,也應該不是同一個對象,因爲他們在不同的類型中被聲明的,所以在不同的常量池中,事實證明我的理解是錯的。

如:
public class A{
     public String s = "x";
}
public  class B{
     public String s = "x";
}
之前的理解是,因爲類A與類B類型不一樣(A,B分別維護一個常量池,各自的常量池中的s應該不是指向同一個對象的),那麼用"=="去比較兩個類裏面的字符串s時,應該返回false。但實際上返回的是true。因爲虛擬機實際上是對String這一類型維護了一個常量池,所以常量池中常量"x"就只有一份對象存在。
下面的例子可以作爲以後實驗時理解用。
public class Test {

    public static void printStr(String s1, String s2) {
       if (s1 == s2) {//判斷
           System.out.println(s1 + " " + s2 + " True");
       } else {
           System.out.println(s1 + " " + s2 + " False");

       }
    }

    // 測試兩個線程中的字符串是否是同一個字符串

    public static void main(String a[]) throws InterruptedException {

       Object lock = new Object();// 線程鎖對象

       StringThreadable fs = new StringThreadable();
       fs.setStrclass(HoldString1.class);
       fs.setLock(lock);
       Thread t1 = new Thread(fs);// 第一個線程

       StringThreadable ss = new StringThreadable();
       ss.setStrclass(HoldString2.class);
       ss.setLock(lock);
       Thread t2 = new Thread(ss);// 第二個線程

       // 執行第一個線程
       synchronized (lock) {
           t1.start();
           lock.wait();
       }

       // 第一個線程執行完後,執行第二個線程
       synchronized (lock) {
           t2.start();
           lock.wait();
       }

       String s1 = fs.getStr(), s2 = ss.getStr();
       printStr(s1, s2);

       String ts1 = fs.getThreadStr(),ts2 = ss.getThreadStr();
       printStr(ts1, ts2);

    }
}

public class StringThreadable implements Runnable{
    private String str;
    private Object lock;
    private Class strclass;
    private String threadStr="ThreadStr";
    
    public void setLock(Object lock) {
       this.lock = lock;
    }

    public void run() {
       synchronized(lock){
           if (strclass.equals(HoldString1.class)){
               this.str=(new HoldString1()).getStr();
               System.out.println("HoldString1:"+str);
           }
               
           else{
               this.str=(new HoldString2()).getStr();
               System.out.println("HoldString2:"+str);
           }
               
           lock.notifyAll();
       }
    }

    public String getStr(){
       return this.str;
    }

    public void setStrclass(Class strclass) {
       this.strclass = strclass;
    }

    
    public String getThreadStr() {
       return threadStr;
    }

    
    
}


//持有String的對象
public class HoldString1 {

    
    private String str  "Gulshan";
    
    public String getStr(){
       return this.str;
    }
}


//持有String的對象
public class HoldString2 {

    
    private String str = "Gulshan";
    
    public String getStr(){
       return this.str;
    }
}

  • if String objects having the same data are created using a constant expression, a string literal, a reference to an existing string, or by explicitly using the intern() method, their references will be the same 

  • if String objects having the same data are created explicitly with the new operator or their values are computed at runtime, their references will be different
  • 參考:http://www.janeg.ca/scjp/lang/strLiteral.html
  • 參考:《What is String literal pool?http://www.xyzws.com/Javafaq/what-is-string-literal-pool/3

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