Test Killer, Questão 91, está errada?

Galera,

estou resolvendo as questões do mock Test Killer e fiquei confuso com a questão 91.

Deem uma olhada nela:

11. public String makinStrings() {	
12.	String s = "Fred";	
13.	s = s + "47";	
14.	s = s.substring(2, 5);	
15.	s = s.toUpperCase();	
16.	return s.toString();	
17. } 

A pergunta da questão é: How many String objects will be created when this method is invoked?

As respostãs são:

[quote]A. 1
B. 2
C. 3
D. 4
E. 5
F. 6[/quote]

Para mim, são 5…

linha12, criamo a string “Fred”.
linha 13, criamo a string “47” e "Fred47"
linha 14, criamo a string "ed4"
linha 15, criamo a string "ED4"
linha 16, retornamos “ED4” mas essa string já se encontra no pool, então não criamos um novo Objeto.

A resposta para a questão no Test Killer é C, ou seja 3.
Isso faz algum sentido??

Bem estranho. Acho que são seis.

e aquele .toString() ali embaixo? Será que cria uma nova? Se for, são seis.

Mas três? Nem fu******.

bom, o toString não cria um novo objeto. Apenas retorna a referência para o próprio objeto:

o método substring com certeza retorna uma nova String:

A dúvida é só no toUpperCase… teoricamente deveria criar um novo objeto String pq String é imutável mas na API não diz nada explicitamente que cria uma nova String. O teste tb fala que são criados 3 objetos…

Alguém sabe?

Já descobri uma explicação, pelo menos 90% dela. As strings literais são criadas em tempo de compilação ou é quando as classes são carregadas pela JVM. Ou seja, quando o método é invocado, “Fred” e “47” já estavam criados.

Sendo assim, tirando 2 da minha resposta, que era 5. Ficam 3. :slight_smile:

[quote=raphaelrabadan]Já descobri uma explicação, pelo menos 90% dela. As strings literais são criadas em tempo de compilação ou é quando as classes são carregadas pela JVM. Ou seja, quando o método é invocado, “Fred” e “47” já estavam criados.
Sendo assim, tirando 2 da minha resposta, que era 5. Ficam 3. :-)[/quote]

:arrow: Em alguns testes, ou melhor em vários desses simulados uma coisa é bem certa, o código vai ter o seu comportamento pela a intenção da JVM e ou seja, quando vc bate o olho no código ira pensar em termos de algoritmo ou buscará algo pela regra de OO, entretanto a VM tem particularidades preempitivas que vão ter prioridade ao comportamento da VM vigente, temos ai as versões 1.4, 1.5, 1.6 e 1.7, na certa você vai ter execuções onde o compilador interpretará o código e executará pela a regra da JVM naquele momento.

Raphael,

Essa questão está errada. São 5 Strings.

Dê uma olhada na implementação da classe String:
http://www.docjar.com/html/api/java/lang/String.java.html

toUpperCase pode ou não criar um novo objeto. Se a String não precisar de upperCase, ou seja, já estiver em maiúsculas o método retorna o próprio objeto. Mas isso não vem ao caso aqui. Só curiosidade.

O caso é que esse teste tá errado.

Strings criadas: “Fred”, “47”, “Fred47”, “ed4” e “ED4”

Pelo que entendi é o seguinte:

primeira string é criada: "Fred"
na outra linha em: s = s + “47”; o compilador na verdade transforma o + em um stringbuffer e da um append… isto faz ele criar apenas o “47”, logo apos no substring não nessecita-se criar outra string pois a string ali existe so precisa pegar um “pedaço” dela isto a baixo nivel deve ser feito alterando a posição do ponteiro nos caracteres da string ou seja não gera outra… em seguida no toUpperCase() é gerado outra string em maiuscula… dai totaliza-se 3…

O toString retorna a própria string, e não a referencia ao objeto.

Se olharmos dentro da implementação do toUpperCase()

       /* Now check if there are any characters that need to be changed. */
        scan: {
            for (firstUpper = 0 ; firstUpper < len ; firstUpper++) {
                char c = value[off+firstUpper];
                if (c != Character.toLowerCase(c)) break scan;
            }
            return this;
        }

Se não for necessária alteração voltará a mesma String, logo nenhum objeto é retornado.

No teste há alterações a serem feitas, logo irá retornar um novo objeto.

O compilador não transforma uma String em um StringBuffer !!!

Chrono,

Eu disse:

luistiagos,

Acho que vc está confundindo as coisas. O compilador não transforma nada em StringBuffer.

Abraço,

internamente por questões de performase ele deve fazer alguma especie de buffer… pois seria muita burrice uma criar um novo objeto s+“47” qdo se pode simplismente juntar os caracters… creio que internamente ele deva fazer algo semelhante a um stringbuffer por questoes de performace porem não sei como isto funciona… alguem sabe?

luistiagos,

Entre no link: http://www.docjar.com/html/api/java/lang/String.java.html e veja como é implementada a classe String.

Abraço,

Se vc nao sabe, não venha aki supor coisas, e confundir quem ta querendo aprender amigo.

ok… mas isto não responde a pergunta do +
oq este + faz? gera uma outra string o que não é muito inteligente ou junta outra string (a esta altura a string ja esta no pool de strings…)

Olha este trecho do livro da Kathy Sierra

[quote]We’ll finish this section by presenting an example of the kind of devilish String question you might expect to see on the exam. Take the time to work it out on paper (as a hint, try to keep track of how many objects and reference variables there are, and which ones refer to which).

String s1 = "spring ";
String s2 = s1 + "summer ";
s1.concat("fall ") ;
s2.concat(s1);
s1 += "winter ";
System.out.println(s1 + " " + s2);

What is the output? For extra credit, how many String objects and how many reference variables were created prior to the println statement?

Answer: The result of this code fragment is “spring winter spring summer”. There are two reference variables, s1 and s2. There were a total of eight String objects created as follows: “spring”, "summer " (lost), “spring summer”, “fall” (lost), “spring fall” (lost), “spring summer spring” (lost), “winter” (lost), “spring winter” (at this point “spring” is lost). Only two of the eight String objects are not lost in this process.

Important Facts About Strings and Memory
In this section we’ll discuss how Java handles String objects in memory, and some of the reasons behind these behaviors.

One of the key goals of any good programming language is to make efficient use of memory. As applications grow, it’s very common for String literals to occupy large amounts of a program’s memory, and there is often a lot of redundancy within the universe of String literals for a program. To make Java more memory efficient, the JVM sets aside a special area of memory called the “String constant pool.” When the compiler encounters a String literal, it checks the pool to sec if an identical String already exists. If a match is found, the reference to the new literal is directed to the existing String, and no new String literal object is created. (The existing String simply has an additional reference.) Now we can start to see why making String objects immutable is such a good idea. If several reference variables refer to the same String without even knowing it, it would be very bad if any of them could change the String’s value.

You might say, “Well that’s all well and good, but what if someone overrides the String class functionality; couldn’t that cause problems in the pool?” That’s one of the main reasons that the String class is marked final. Nobody can override the behaviors of any of the String methods, so you can rest assured that the String objects you are counting on to be immutable will, in fact, be immutable.

[/quote]

O compilador não vai pré-julgar uma coisa dessas, senão questões como esta não existiriam, pois dependeriam daquilo que o compilador acha que é o correto.

O desenvolvedor que, numa aplicação real, vai decidir a melhor maneira de utilizar a api.(utilizando o StringBuffer ou StringBuilder(java 1.5 ou superior))

Na minha opinião o raphaelrabadan está correto. Quando se instancia uma classe todas as strings literais da classe vão para a memória automaticamente.

Quando se chama o método, com certeza a classe já está instanciada, logo…a resposta é C.
Se for realmente isso, eu teria errado.

:lol:

Kathy Sierra
Bert Bates

:idea: Para tornar a linguagem Java mais eficiente no uso da memória, o JVM deixa reservada uma área especial chamada “Pool constante de String”.Quando o compilador encontra um string literal, verifica o pool para ver se já existe uma idêntica.

When the compiler encounters a String literal, it checks the pool to sec if an identical String already exists.

:arrow: Isso pode ser considerado não como pré-julgar, mas sim algo preempitivo pela regras da VM aos objetos String e a memória.

Na minha opinião, a questão está correta.

As strings criadas são:

String s = “Fred”; // 1- “Fred”

s = s + “47”; // 2- “Fred47”

s = s.substring(2, 5); //3- “ed47”

toUpperCase não cria um novo objeto.

Flws!

Qualquer compilador/interpretador decente otimiza o codigo na geração do bytecode… coisas como:

int a = 2 * 7;
a += 4;

na hora de interpretar transforma-se em isto:
a = 2 * 7 + 4;

otimizando o codigo…
para strings ele pode otimizar tbm… isto não é pré-julgar… é apenas otimizar…

isto:

String s = “ola”;
s += " Mundo";

é a mesma coisa que isto:

String s = “ola Mundo”;

so que a segunda forma é a forma otimizada…
fazer pequenas otimizações em tempo de interpretação e geração de bytecode é algo que a maioria dos compiladores decentes fazem… não sei mas acredito que deva se fazer o mesmo com strings… algo que é fato é a utilização do pool de strings… então creio que deva ter alguma otimização parecida coom esta citada…

[quote=Marcio Duran][quote=ChronoTrigger]

O compilador não vai pré-julgar uma coisa dessas, senão questões como esta não existiriam, pois dependeriam daquilo que o compilador acha que é o correto.

[/quote]

Kathy Sierra
Bert Bates

:idea: Para tornar a linguagem Java mais eficiente no uso da memória, o JVM deixa reservada uma área especial chamada “Pool constante de String”.Quando o compilador encontra um string literal, verifica o pool para ver se já existe uma idêntica.

When the compiler encounters a String literal, it checks the pool to sec if an identical String already exists.

:arrow: Isso pode ser considerado não como pré-julgar, mas sim algo preempitivo pela regras da VM aos objetos String e a memória.[/quote]

Pessoal, a checagem de String literais que vão para o POOL é feito em tempo de compilação, ou seja, a resposta é 3, vou explicar-lhes o porque.

Essa questão realmente é muito, digamos, sacana, mas vamos a ela…
A pergunta diz: “Quantos objetos String são criados quando o MÉTODO É INVOCADO?”

O compilador ao compilar essa classe, encontra essas 2 String literais, “Fred” e “47” e já as coloca no Pool de Strings! Sendo assim, [B]ANTES da INVOCAÇÃO[/B] do método, essas 2 String já foram criadas. Então, ao invocar o método, são criadas as outras 3 Strings que foram ditas, por mim, no primeiro post fazendo a questão correta.

11. public String makinStrings() {	
12.	String s = "Fred";	
13.	s = s + "47";	
14.	s = s.substring(2, 5);	
15.	s = s.toUpperCase();	
16.	return s.toString();	
17. } 

eu tinha dito o seguinte:

[quote]
linha12, criamo a string “Fred”.
linha 13, criamo a string “47” e "Fred47"
linha 14, criamo a string "ed4"
linha 15, criamo a string "ED4"
linha 16, retornamos “ED4” mas essa string já se encontra no pool, então não criamos um novo Objeto. [/quote]

Mas diante do descoberto, 2 dessas Strings já foram criadas antes da invocação! Ou seja, fica assim:

[quote]
linha12, pegamos a String “Fred” do Pool
linha 13, pegamos a string “47” do Pool e criamo a string "Fred47"
linha 14, criamo a string "ed4"
linha 15, criamo a string "ED4"
linha 16, retornamos “ED4” mas essa string já se encontra no pool, então não criamos um novo Objeto. [/quote]

Resultado: 3

Delvish question!

Será que cai algo assim na certificação? Vocês, certificados, iluminem essa minha dúvida :stuck_out_tongue_winking_eye:

Bem amigo, pelo que me consta, as questoes do test killers sao tiradas da prova. Ou simulando elas. entaum cai sim.