虚拟机 常量池

之前将"虚拟机必须为每个被装载的类型维护一个常量池"这句话理解成了不同的类型的类声明中如果有相同类型的对象域,即使对象域持有的字面量一样,也应该不是同一个对象,因为他们在不同的类型中被声明的,所以在不同的常量池中,事实证明我的理解是错的。

如:
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

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