Como o Java armazena Strings e como a substring funciona internamente?

class StringTesting { public static void main(String args[]) { String str = "abcd"; String str1 = new String("abcd"); String str2 = str.substring(0,2); String str3 = str.substring(0,2); String str4 = str.substring(0,str.length()); String str5 = str1.substring(0,2); String str6 = str1.substring(0,2); String str7 = str1.substring(0,str1.length()); System.out.println(str2 == str3); System.out.println(str == str4); System.out.println(str5 == str6); System.out.println(str1 == str7); } } 

Aqui está a saída que recebo no java 1.6.0_27:

 false true false true 

Alguém pode por favor explicar a saída. Eu sei que o Java diferencia entre String armazenada no heap e String armazenada na String “common pool” (que pode ser internada). Internamente, como é sua representação diferente? Como isso altera o algoritmo de substring. Por favor, cite livro / artigo / blogs, etc., sempre que apropriado.

    Veja os comentários:

      String str = "abcd"; // new String LITERAL which is interned in the pool String str1 = new String("abcd"); // new String, not interned: str1 != str String str2 = str.substring(0,2); // new String which is a view on str String str3 = str.substring(0,2); // same: str3 != str2 String str7 = str1.substring(0,str1.length()); // special case: str1 is returned 

    Notas:

    • Desde o Java 7u6, a substring retorna uma nova string em vez de uma view na string original (mas isso não faz diferença para esse exemplo)
    • Caso especial quando você chama str1.substring(0,str1.length()); – veja o código:

       public String substring(int beginIndex, int endIndex) { //some exception checking then return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen); } 

    EDITAR

    O que é uma visão?

    Até o Java 7u6, um String é basicamente um char[] que contém os caracteres da string com um deslocamento e uma contagem (ou seja, a string é composta de caracteres de count a partir da posição de offset no char[] ).

    Ao chamar substring, uma nova string é criada com o mesmo char[] mas com um offset / count diferente, para criar efetivamente uma exibição na string original. (Exceto quando count = length e offset = 0 conforme explicado acima).

    Desde o java 7u6, um novo char[] é criado toda vez, porque não há mais campo count ou offset na class de string.

    Onde a piscina comum é armazenada exatamente?

    Esta é uma implementação específica. A localização da piscina mudou nas versões recentes. Em versões mais recentes, ele é armazenado no heap.

    Como o pool é gerenciado?

    Características principais:

    • Literais de string são armazenados no pool
    • As strings internas são armazenadas no pool ( new String("abc").intern(); )
    • Quando uma cadeia S é internada (porque é um literal ou porque intern() é chamado), a JVM retornará uma referência a uma cadeia no conjunto se houver uma que seja equals a S (portanto, "abc" == "abc" deve sempre retornar true).
    • As cadeias de caracteres no conjunto podem ser coletadas como lixo (o que significa que uma cadeia de caracteres internada pode ser removida do conjunto em algum estágio, se ficar cheia)

    String é um object imutável.

    String#subString – cria uma nova String. Fonte

    No código é [open jdk 6] –

      public String substring(int beginIndex, int endIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } if (endIndex > value.length) { throw new StringIndexOutOfBoundsException(endIndex); } int subLen = endIndex - beginIndex; if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen); }