Qual a quantidade de Objetos Strings no heap?

Estou com dúvida nesta questão.
[color=blue]
Given:
[/color]

public String makinStrings() {
   String s = "Fred";
   s = s + "47";
   s = s.substring(2, 5);
   s = s.toUpperCase();
   return s.toString();
}

[color=blue]
How many String objects will be created when this method is invoked?
A. 1
B. 2
C. 3
D. 4
E. 5
F. 6
[/color]
Desenhei todos os objetos criados, mas na minha opinião são criados 4 objetos (Resposta D):

Na linha 2 é criado o objeto "Fred"
Na linha 3 é criado o objeto "Fred47"
Na linha 4 é criado o objeto “ed4” e
na linha 5 é criado o objeto “ED4”

Sendo que no mock fala qua a resposta certa é a C (3 objetos).
Alguém sabe porque ? :?:. Ou será que está com erro :evil:.

Reestréia no fórum… :roll:

Acho que são 3 mesmo… veja só:

na linha 3 não há criação de 1 novo objeto a operação é feita e atribuida pelo mesmo objeto, nas linhas seguintes é criado 1 objeto novo pelo retorno das funções que são atribuidas a mesma variavel de referencia s.

Essa questão ja surgiu 500 vezes aqui no fórum, da uma pesquisada até mesmo no google que você encontra.
String s = “Fred”; e “47”, Não são criados novos objetos não, eles já existem no pool de strings.
s = s + “47”; É criado quando junta a variável s com o “47” para formar o “Fred47”.
s = s.substring(2, 5); É criado um novo objeto "ed4"
s = s.toUpperCase(); É criado um novo objeto “ED4” , se já fosse em maiúsculo ele não iria criar, iria pegar o ja existente no pool de strings.
return s.toString(); Nada é criado ja que ele retorna por copia.

[quote=taaqui]Essa questão ja surgiu 500 vezes aqui no fórum, da uma pesquisada até mesmo no google que você encontra.
String s = “Fred”; e “47”, Não são criados novos objetos não, eles já existem no pool de strings.
s = s + “47”; É criado quando junta a variável s com o “47” para formar o “Fred47”.
s = s.substring(2, 5); É criado um novo objeto "ed4"
s = s.toUpperCase(); É criado um novo objeto “ED4” , se já fosse em maiúsculo ele não iria criar, iria pegar o ja existente no pool de strings.
return s.toString(); Nada é criado ja que ele retorna por copia.[/quote]

No retorno eu pensei na copia também… Vi isso a pouco tempo. :smiley:

Mas podia jurar que no momento de atribuição String s = “Fred” cria-se 1 objeto… Agora fiquei com duvida…

A minha duvida fica no caso da atribuição a s de uma string, caso eu atribui-se String s = “Fred” + “47” então nesse caso iria criar um objeto correto?

[quote=taaqui]Essa questão ja surgiu 500 vezes aqui no fórum, da uma pesquisada até mesmo no google que você encontra.
String s = “Fred”; e “47”, Não são criados novos objetos não, eles já existem no pool de strings.
s = s + “47”; É criado quando junta a variável s com o “47” para formar o “Fred47”.
s = s.substring(2, 5); É criado um novo objeto "ed4"
s = s.toUpperCase(); É criado um novo objeto “ED4” , se já fosse em maiúsculo ele não iria criar, iria pegar o ja existente no pool de strings.
return s.toString(); Nada é criado ja que ele retorna por copia.[/quote]

apenas para ficar claro mesmo… o fato é que a pergunta fala

How many String objects will be created when this method is invoked?

ou seja… a pergunta aqui é especifica, pergunta no momento que o método é invocado… antes mesmo do método ser invocado as strings “Fred” e “47” já estão no pool…

porem se vc conciderar um programa completo e a pergunta for quantas String o programa cria, ai mesmos essas do pool vão entrar na conta o que resultaria em 5…

ok?

Vamos ver se eu entendi !! :smiley:

Como criamos os objetos “Fred” e “47” usando o operador “=” ( [color=red]Sem dar new()[/color] ) eles foram criados direto no pool de Strings.
E o pool de Strings é populado antes do método makingString() ser chamado.
Então partimos do suposto que essas duas Strings foram criadas antes do método ser chamado.

Aí quando chamamos o método makinString() criamos 3 objetos.

  1. O objeto “Fred47” criado na linha 3
  2. O objeto “ed4” criado na linha 4
  3. O objeto “ED4” criado na linha 5

É isso ?
:?: :?: :?:

Copiando um gráfico muito explicativo :lol: (by taaqui) e alterando para o cenário deste exercício seria assim que ficariam os objetos no heap e no pool ?

[quote=Lavieri][quote=taaqui]Essa questão ja surgiu 500 vezes aqui no fórum, da uma pesquisada até mesmo no google que você encontra.
String s = “Fred”; e “47”, Não são criados novos objetos não, eles já existem no pool de strings.
s = s + “47”; É criado quando junta a variável s com o “47” para formar o “Fred47”.
s = s.substring(2, 5); É criado um novo objeto "ed4"
s = s.toUpperCase(); É criado um novo objeto “ED4” , se já fosse em maiúsculo ele não iria criar, iria pegar o ja existente no pool de strings.
return s.toString(); Nada é criado ja que ele retorna por copia.[/quote]

apenas para ficar claro mesmo… o fato é que a pergunta fala

How many String objects will be created when this method is invoked?

ou seja… a pergunta aqui é especifica, pergunta no momento que o método é invocado… antes mesmo do método ser invocado as strings “Fred” e “47” já estão no pool…

porem se vc conciderar um programa completo e a pergunta for quantas String o programa cria, ai mesmos essas do pool vão entrar na conta o que resultaria em 5…

ok?[/quote]

Desculpe mas, as String’s “Fred” e “47” não são criadas no momento da chamada do método?

desde já agradeço

Pessoal, essa questão já foi AMPLAMENTE discutida nestes tópicos abaixo:

http://www.guj.com.br/posts/list/120952.java
http://www.guj.com.br/posts/list/116352.java

Essa questão reaparece no fórum sempre, de tempos em tempos, e SEMPRE gera uma grande discussão. Então vamos aproveitar as que já foram sanadas, pra não ficar repetitivo.

a mim so ficou uma única duvida sobre o assunto, todo resto ja entendi, e sei que essa duvida especifica não se remete ao exame, mas enfim, vamos la…

Segundo bilhoes do trexo do livro q li, e em todo canto que vejo, fala-se, todo objeto que é criado reside no Heap…

E fala-se tb sobre o pool de strings literais…

minha duvida é…

public String blablabla = "etc" + "blablabla";

ao carregar a classe onde tem essa declaração, caso ainda não exista no pool, uma referencia a String com o conteúdo “etc” e a “blablabla”, o que ocorre ??

ate onde entendi, é criado uma string “etc” no Heap, uma referencia a essa String, é guardado num especie de conteiner de referencia no pool de Strings, e assim, mesmo sendo a string inalcasável (desculpem meu bom portugues) pelo programa, o GC nunca apagara a String, por exestir uma referencia a ela, la no pool de String

o mesmo aconteceria a string literal “blablabla” …

Sendo assim, a minha dúvida é essa: a String, criada a partir de um literal, residiria como todas as outras no Heap ok ?? no pool de string, só existe a referencia a esta string ?? uma especia de Collection, que é consultada, sempre que uma outra literal é encontrada no programa para poupar de criar vários objetos strings atoa…

a duvida principal é essa… o Objeto String esta sempre no Heap ?? independete de sua referencia so existir apenas no pool de strings ?

e para que fique claro a duvida, sem deixar interpretações dubias, NÃO EXISTE OBJETO STRING FORA DO HEAP, portanto NÃO existe string unica e exclusivamente internada dentro do pool de strings? a String esta sempre no Heap, e pode existir, ou não, referencia a ela no pool de Strings, mais é apenas uma referencia a ela, e não uma string proprieamente dita… é isso ?

Ninguem ?? sabe ? sobre o post acima ?

Deixa eu fazer uma pergunta para você, se você responder vai conseguir sanar as suas duvidas.
Qual a diferença entre, String p1 = “guj” e String p1 = new String("guj);?
E o que acontece quando eu uso o método intern?

[quote=taaqui]Deixa eu fazer uma pergunta para você, se você responder vai conseguir sanar as suas duvidas.
Qual a diferença entre, String p1 = “guj” e String p1 = new String("guj);?
E o que acontece quando eu uso o método intern?[/quote]

não resolve minha duvida, e sim eu sei a diferença…

String p1 = "guj"; A JVM cria um objeto String (no momento em que a classe é carregada), cuja seu valor é um array char[] = {‘g’,‘u’,‘j’}, o pool de strings mantem uma referencia a este objeto, mesmo que a aplicação nunca passe por este ponto, onde esta descrito, p1 = “guj”, mesmo assim, esse objeto já estara criado, e o pool de string vai ter uma referencia a ele…

quando o aplicativo, passar por este ponto, a JVM vai procurar a referencia no pool de strings, para o valor char[] {‘g’,‘u’,‘j’} e vai passar a referencia para p1… sem criar nenhum objeto a mais neste momento, o objeto ja esta criado, desde a hora que a classe foi carregada…

String p1 = new String("guj"); Muito parecido com o primeiro caso, a string com o valor char[] = {‘g’,‘u’,‘j’} é criada tb no momento que a classe e carregada, sua referencia fica no pool… mesmo antes do aplicativo passar por esse ponto…

porem ao passar pelo ponto do programa, a JVM busca o objeto que esta gurdado no pool, com a referencia a char[] = {‘g’,‘u’,‘j’} … mas não passa a p1, ele passa ao construtor de String(String s) … esse construtor vai construir um novo objeto, para tal ele vai fazer uma copia de da array de char[] {‘g’,‘u’,‘j’} … não será a mesma array, vai ter o mesmo conteúdo, porem é só uma copia… esse novo objeto será passado a p1…

neste segundo caso, exitem 2 strings… uma que o pool de strings faz referencia, outra que p1 faz referencia, as duas são equals, porem não são ==, pois são referencia a objetos diferentes…

o método String.intern()… busca no pool de strings por uma referencia igual ao conteúdo da string, não encontrando, ele adciona a propria referencia ao pool, e retorna sempre a referencia do pool…

mas a minha pergunta é… as Strings do pool não residem nele não é ??
esta Strings, assim como todos os outros objetos java existem no Heap?
e no pool só há uma lista de referencias para estas Strings, que estão no Heap…

essa é a minha duvida… os objetos, apesar de ver em varios posts, que eles existem internados no pool de strings, eu acredito que eles existam no Heap e o que existem internado no pool, são suas referencias…

eu acredito, que por exemplo, neste trecho, os objetos sejam assim

String str = new String("java"); String srt3 = "java"; String srt2 = "java";ou seja… srt3 e srt2, referenciam a um mesmo objeto, que é o mesmo referenciado pelo pool de strings, e este objeto está no Heap, e não no pool.
srt aponta para um outro objeto, que foi criado a partir do construtor String(String s)…

e logicamente…srt != srt2 && str != str3 // é verdadeiro esrt2 == srt3 // é verdadeiroesrt.equals(str2) && srt2.equals(srt3) && srt3.equals(srt) // é verdadeiro

[quote=Lavieri]eu acredito, que por exemplo, neste trecho, os objetos sejam assim

String str = new String("java"); String srt3 = "java"; String srt2 = "java";ou seja… srt3 e srt2, referenciam a um mesmo objeto, que é o mesmo referenciado pelo pool de strings, e este objeto está no Heap, e não no pool.
srt aponta para um outro objeto, que foi criado a partir do construtor String(String s)…

e logicamente…srt != srt2 && str != str3 // é verdadeiro esrt2 == srt3 // é verdadeiroesrt.equals(str2) && srt2.equals(srt3) && srt3.equals(srt) // é verdadeiro

[/quote]

Olá Lavieri.

Esse assunto já deu mtas discussões em outros tópicos e essa sua dúvida já foi respondida nos mesmos. Vou reforçar novamente então o que ocorre:

No caso de referências literais de Strings presentes em tempo de COMPILAÇÃO, essas literais são armazenadas no Pool de Strings (para fins de otimização de desempenho da JVM no caso de existência de referências similares a uma mesma ocorrência). NÃO É CRIADO UM OBJETO STRING NO HEAP CORRESPONDENTE À ESSA LITERAL PRESENTE NO POOL . A variável de referência, aponta apenas para o instância no POOL. Portanto, essa figura que vc postou não está correta.

Essas instâncias que estão armazenadas no Pool, NÃO SÃO CANDIDATAS AO GARBAGE COLLECTOR. Você deve saber que o GC SÓ ATUA NO HEAP. Portanto, se a memória ocupada por elas for limpa em algum momento, não será pelo GC, isso vc pode ter certeza.

Acho que isso já resolve o restante de suas dúvidas que podem surgir…Mas enfim, se ainda assim quiser uma fonte mais rica em detalhes, inclusive com referências à JLS, acesse:
http://www.coderanch.com/t/438724/Java-General-beginner/java/Garbage-Collection-String

Espero ter ajudado.

bom, apenas esclarecendo, nunca poderiam ser apagadas, as strings, da forma como ficou a figura que postei, por definição, o coletor de lixu, so apaga Objetos impossiveis de serem alcançados pelo programa, e qualquer string no pool, pode ser alcançada usando-se o método intern() … portanto não há como apagar as Strings do pool, visto que suas referencias não morreram para o programa…

A duvida é realmente só essa… se o Objeto String, é criado e reside no Pool, não exitindo assim no Heap, ou se ele é criado no Heap, assim como todos, e o pool só é uma referencia a ele… a forma de só existir no Heap a mim parece algo mais logico…

Para vc ficar um pouco mais intrigados, o String esta no pool ? e não no heap ?? então onde esta o objetos char[] da propriedade value dentro do String ?? esta no Heap ou no Pool ?? como metade do objeto poderia estar em um lugar e metade em outro ?? pq eu posso guardar referencia do char[] fora do pool, ve esse exemplo a seguir

Invasão de Privacidade[code]import java.lang.reflect.Field;
import java.util.Arrays;

public class InvasaoDePrivacidade {

public static void main(String[] args) {
    String str = "guj";
    //supostamente str é imutavel e seu conteúdo é "guj" e esta no pool
    ViolacaoDePrivacidade vdp = new ViolacaoDePrivacidade("guj");

    //Strings antes da alteração
    System.out.println("guj"); //imprimindo um literal "guj"
    System.out.println(vdp); //imprimindo o conteúdo de vpd
    System.out.println(str); //imprimindo o conteudo da str

    System.out.println();
    System.out.println("'Alterando o pool de Strings' => setCharAt(0, 'H')");
    vdp.setCharAt(0, 'H');
    System.out.println(vdp); //imprimindo o conteúdo alterado de vdp
    System.out.println("guj"); //como um literal "guj" pode imprimir "Huj"?
    System.out.println(str); //imprimindo o conteudo da str
    System.out.println("guj" == "Huj"); //obviamente false
    System.out.println("guj".equals("Huj")); //estranhamento true

    //Como posso alterar o pool de strings e conectar o objeto
    //char[] = {'g','u','j'} a outro objeto que esta no heap?
    //e depois aterar seu valor no pool e no heap ?
    //Por isso acredito que todos os objetos estão no Heap!
}

}

class ViolacaoDePrivacidade {
private char[] source;
private static final Field charField = getField();

private static Field getField() {
    Field stringCharField = null;
    try {
        stringCharField = String.class.getDeclaredField("value");
        stringCharField.setAccessible(true);
    } catch (Exception ex) {}
    return stringCharField;
}

public ViolacaoDePrivacidade(String source) {
    this.source = getChars(source);
}

private char[] getChars(String source) {
    char[] result = null;
    try { result = (char[])charField.get(source); }
    catch (Exception ex) {}
    return result;
}

public void setCharAt(int index, char c) {
    this.source[index] = c;
}

public @Override String toString() {
    return Arrays.toString(source);
}

}[/code]

roda esse aplicativo que vc verá que o resultado é esse

[code]guj
[g, u, j]
guj

‘Alterando o pool de Strings’ => setCharAt(0, ‘H’)
[H, u, j]
Huj
Huj
false
true[/code]

“Como posso alterar o pool de strings e conectar o objeto char[] = {‘g’,‘u’,‘j’} a outro objeto que esta no heap ?”
‘e depois aterar seu valor no pool e no heap ?’
‘Por isso acredito que todos os objetos estão no Heap!’

Se alguem souber de uma forma pratica, de verificar se um objeto esta no Heap… tentei demonstrar que um Objeto, ViolacaoDePrivacidade, que tenho certeza estar no Heap, com seu objeto interno source que é um char[] que tb acredito estar no Heap, e que por invasão da privacidade de String, é a mesma array de char que da String “guj” …

alterei o array do objeto ViolacaoDePrivacidade, que mostrou o mesmo reflexo na string literal, pois os 2 referenciam a mesma array de chars, e assim “guj” passou a ser “Huj” …

posso estar engando, mas acredito que os objetos Strings ficam no Heap, e o que temos no pool, é apenas referencia a ele…

se vc inserir ao final do programa acima, apos a linha 24 System.out.println((new String(new char[] {'g','u','j'})).intern() == "guj"); System.out.println((new String(new char[] {'g','u','j'})).intern().equals("guj")); System.out.println(new String(new char[] {'g','u','j'}));vai obter a saida… false false guj

Bom, vc perguntou e foi respondido. Não há atuação do GC no Pool de Strings.

Já foi dada a resposta tbm:

A resposta continua a mesma: No caso de Strings literais, não é criado nenhum objeto no heap, eles residem apenas no pool. Pra ser criado no heap é necessário que seja instanciado pelo método construtor da classe String.

Pode parecer estranho pra vc esse comportamento, mas é o que ocorre realmente. Consulte as fontes presentes no link que citei no post acima.Pode acreditar no que está lendo.

flw.

That’s true only if you’re talking about the constant pool, which is a region in a .class file. That’s for all constants referenced in the class definition, not just strings, so I don’t think that’s what the rest of this thread has been about.

If you’re talking about the String intern pool, that’s shared with String’s intern() method - which means it certainly can grow. It can also grow if you keep loading new classes into the JVM.

It’s also possible for items in the intern pool to be garbage collected, but that’s fairly unusual, at least for literals, since such object also have other references from the class definition. You can think of the intern pool as a WeakHashMap - by itself, the intern pool will not prevent GC of its contents. But if there are any other references to a String in the pool, those can prevent GC. And it turns out that such references are maintained by the class in memory, after being loaded by a ClassLoader. So the only way for a literal to get GC’d is for the class to get unloaded. Which in turn requires that the ClassLoader that loaded it is also eligible for GC. Which doesn’t happen often in beginner code, but it’s not unusual in something like an app server. Bottom line, items in the intern pool can be GC’d, but it’s complex and unusual.[/quote]

pelo que li dessa resposta q é a mais completa, o meu intendimento continua o mesmo… as Strings estão no Heap, como todas as outras, o pool é apenas uma tabela de referencia, como se fosse uma WeakHashMap … gostira de uma fonte melhor q falasse claramento sobre isso, para sanar a minha duvida (que é apenas uma curiosidade, mas que eu gostaria muito de saber hehehe)…

eu postei la a duvida no forum, continuando esse post, meu ingles é pessimo (assim como meu portugues) … eu espero que eles entendam minha pergunta…

Ps.: minha duvida não era em si sobre Garbage Collection, e sim sobre se os objetos literais Strings residem no Heap e tem apenas referencia a elas no pool.