Java中String直接復制和new String創建對象的區別以及equals和==的區別和效率對比


編程語言中的問題很多時候我們看似懂,實際不懂,因為很多時候看不到更多的情況,從而缺少對這些看不到的情況的認知和解釋。

今天mark一下String和new String()的區別。其實很簡單。

String s1 = new String("string") // 這是一個對象,對象存放在堆里面

String s2 = "string" //這是一個字符串常量,存放在常量池中,也就是方法區里面

String s3 = "string" // ....

以上就是這兩個最大的區別。每一個對象有自己的內存地址;而字符串常量雖然可能變量名不同,但是只要常量的值相同,他們的內存地址都是常量池中的那一個內存地址,是等同的。

所以s2 == s3 是true,s1 == s2 是false,而s1.equals(s2)是true。
“==” -> 代表同一個東西(如對象,常量等等)

“.equals()” -> 代表變量所表示的值相同。也就是比較變量的hash值

注意一點的是:常量池這個東西,是針對一個java進程來說的,所以不管一個常量在哪里:在文件 A.java 也好,文件B.java也好,不管這個變量是一個什么類型:private也好,static也好,只要這些文件運行在了一個java進程中並且包含相同值得字符串常量(更大范圍的說是常量),他們就等是相等(==)的,都指向同一個內存地址。(當然,出現新的字符串常量就會在常量池中開辟新的地址了)

引用深入理解Java虛擬機的原話:“運行時常量池(Runtime Constant Pool)是方法區的一部分。class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池(Constant Pool Table),用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載后進入方法去的運行時常量池中存放。”

代碼測試:不同類,不同文件中的不同變量名的相同值得字符串常量

public class App {
    private static String aString = "abc";
    public static void main(String[] args) {
        String aString = "abc";
        String bString = new String("abc");
        String cString = "abc";
        System.out.println(aString == new T().bString);
        System.out.println(aString == T.aString);
        System.out.println(aString == App.aString);
        System.out.println(aString == cString);
        System.out.println(aString == bString);
        System.out.println(aString.equals(bString));
    }
}

class T {
    static String aString = "abc";
    String bString = "abc";
}

程序輸出:

true
true
true
true
false
true

考慮一點的是:對於常量來說"=="和"equals"有沒有效率上的差別的?答案是沒有,測試代碼:

public class App {
    private static String aString = "abc";
    public static void main(String[] args) {
        String aString = "abc";
        String bString = new String("abc");
        String cString = "abc";
        long ctimes = 1000 * 1000 * 1000 * 1000 * 1000;
        long time1 = System.currentTimeMillis();
        for (long i = 0; i < ctimes; i++) {
            if (aString == cString) {

            }
        }
        long time2 = System.currentTimeMillis();
        for (long i = 0; i < ctimes; i++) {
            if (aString.equals(cString)) {

            }
        }
        long time3 = System.currentTimeMillis();
        System.out.println("== time spent = " + (time2 - time1));
        System.out.println("equals time spent == " + (time3 - time2));
    }
}

輸出結果沒有差別,原因其實很簡單,我們去看equals的源碼

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

這下清楚了!!其實this == anObject跟==沒有任何區別的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM