2015-02-10 47 views
2

我知道字符串字面量和新String對象之間的差異,並且也知道它是如何在內部工作的。但是我的問題是這一點的進步。當我們使用new關鍵字創建String對象爲Java-使用新關鍵字創建字符串對象

String str = new String("test"); 

在這種情況下,我們傳遞一個String類型的參數。 我的問題是這個字符串生成的地方 - 堆或字符串常量池還是別的什麼地方?

就我所知,這個參數是一個字符串文字,所以它應該在String常量池中。如果是這樣,那麼intern方法的用法 - 只是將變量str鏈接到常量池?因爲"test"已經可用。

請澄清我,如果我誤解了這個概念。

回答

8

語句String str = new String("test");創建一個字符串對象,它像任何其他對象一樣存儲在堆上。作爲參數傳遞的字符串文字"test"存儲在字符串常量池中。

String#intern()檢查字符串池中是否已有字符串常量。如果已經有一個它會返回它,否則它將創建一個新的並將其存儲在池中。請參閱Javadocs

返回字符串對象的規範表示形式。

最初爲空的字符串池由類String私人維護。

當調用intern方法時,如果池已經包含一個與equals(Object)方法確定的String對象相同的字符串,則返回該字符串。否則,將此String對象添加到池中,並返回此String對象的引用。

由此可見,對於任何兩個字符串sts.intern() == t.intern()爲真,當且僅當s.equals(t)爲真。

從JDK7開始,interned字符串存儲在堆上。這是從release notes of JDK7

在JDK 7,實習字符串不再是永久代Java堆的分配,但在Java堆的主要部分(被稱爲老少皆改爲分配世代),以及應用程序創建的其他對象。此更改將導致更多數據駐留在主Java堆中,永久生成中的數據更少,因此可能需要調整堆大小。由於這種變化,大多數應用程序在堆使用中只會看到相對較小的差異,但是裝載很多類或大量使用方法的較大應用程序將會看到更顯着的差異。

+0

什麼實習方法做 - 只是鏈接? – 2015-02-10 09:04:20

+0

@AnkitSharma - 如果字符串尚未添加到字符串常量池中,調用* intern()*會將該字符串添加到字符串常量池中。 – TheLostMind 2015-02-10 09:05:31

+0

但是在這種情況下''str str = new String(「test」)''test'每次都可以在常量池中使用。 – 2015-02-10 09:18:38

5

使用intern()

public static void main(String[] args) throws IOException { 
    String s = new String(new char[] { 'a', 'b', 'c' }); // "abc" will not be added to String constants pool. 
    System.out.println(System.identityHashCode(s)); 
    s = s.intern();// add s to String constants pool 
    System.out.println(System.identityHashCode(s)); 

    String str1 = new String("hello"); 
    String str2 = "hello"; 
    String str3 = str1.intern(); 
    System.out.println(System.identityHashCode(str1)); 
    System.out.println(System.identityHashCode(str2)); 
    System.out.println(System.identityHashCode(str3)); 
} 

O/P:

1414159026 
1569228633 --> OOPs String moved to String constants pool 

778966024 
1021653256 
1021653256 --> "hello" already added to string pool. So intern does not add it again. 
+0

你是絕對正確的。但是我的困惑是 - 即使你在字符串常量池中沒有'hello',並且你鍵入了'String str = new String(「hello」)'。因此,在這種情況下,首先在池中生成hello',然後字符串對象使用此文字在堆上創建。這意味着'intern'永遠不會在常量池中添加任何文字。 – 2015-02-10 09:30:41

+0

@AnkitSharma - 是的。在這種情況下,intern()不會將「hello」添加到String consatnts池中 – TheLostMind 2015-02-10 09:35:20

3

當您使用String str = new String("test");它會創建兩個對象,一個參考變量。在這種情況下,JVM將在普通(非池)堆內存中創建一個新的字符串對象,文字"test"將被放置在字符串常量池中。變量str將引用堆中的對象(非池)。