Possível erro no livro da Kathy Sierra (SCJP)

29 respostas
felipealbuquerque

Boa tarde, pessoal!

Eu estava resolvendo os exercícios do capítulo 3 (Assignments) e, logo no exercício 2, me deparei com a seguinte questão:

Given:

class CardBoard {
    Short story = 5;
    CardBoard go(CardBoard cb) {
        cb = null;
        return cb;
    }
    public static void main(String[] args) {
        CardBoard c1 = new CardBoard();
        CardBoard c2 = new CardBoard();
        CardBoard c3 = c1.go(c2);
        c1 = null;
        // do Stuff
    }
}

When // doStuff is reached, how many objects are eligible for GC?

A. 0
B. 1
C. 2
D. Compilation fails.
E. It is not possible to know.
F. An exception is thrown at runtime.

Seguindo o meu raciocínio (segundo a seqüência do código):

  1. Um objeto CardBoard é criado e referenciado por c1. A variável de referência story aponta para um objeto Short de valor 5;
  2. Outro objeto CardBoard é criado e referenciado por c2. A variável de referência story desse novo objeto aponta para o mesmo objeto Short, de acordo com a regra citada na página 236, que diz que o código abaixo é válido:
Short s1 = 5;
Short s2 = 5;

System.out.println(s1 == s2); // Imprime true, o que significa que s1 e s2 apontam para o mesmo objeto
  1. O método go(CardBoard) é chamado, com uma cópia da variável de referência c2;
  2. c2, portanto, continua apontando para o mesmo CardBoard;
  3. c3 não aponta para nenhum objeto;
  4. c1 não aponta para nenhum objeto, portanto, como não é referenciado por mais nenhuma variável, o objeto apontado por c1 fica elegível para o Garbage Collector;
  5. Mesmo se c1 for coletado, o Short para o qual c1.story apontava não fica elegível, pois c2.story ainda aponta para esse objeto!
  6. Portanto, a resposta correta, seguindo esse raciocínio, é a resposta B (1)

Entretanto, a resposta correta segundo o livro é a resposta C (2), pois, segundo o livro, o objeto Short também seria elegível.

Colegas de comunidade, vocês concordam comigo?

29 Respostas

T

Você está certo - é a pegadinha em que o revisor do código caiu. Se o código original lesse:

Short story = 12345;

aí teríamos 2 objetos disponíveis para garbage collection.

marcioa1

Jé fazem tres anos que me certifiquei, de forma que estou um pouco enferrujado.

Os objetos C2 e C3 não seriam igual a null ?

[editado] Pensando melhor, C2 não é null não [/editado]

Márcio

P

o livro esta certo…

existem 2 objetos…

vc acertou q o C1 está sujeito ao coletor, SÓ QUE, dentro do seu objeto C1, vc tem uma variavel de instancia q utiliza de um wrapper…entao, assim como vc está deixando o C1 para o GC, vc tb está deixando a referencia do wrapper, SHORT

ok!?

marcioa1

pardal_nb:
o livro esta certo…

existem 2 objetos…

vc acertou q o C1 está sujeito ao coletor, SÓ QUE, dentro do seu objeto C1, vc tem uma variavel de instancia q utiliza de um wrapper…entao, assim como vc está deixando o C1 para o GC, vc tb está deixando a referencia do wrapper, SHORT

ok!?

???

Qual o nome desta referência do wrapper ? O que é referÊncia do wapper ? Quem é o wapper ? :oops:

???
Márcio

dreamspeaker

pardal_nb:
o livro esta certo…

existem 2 objetos…

vc acertou q o C1 está sujeito ao coletor, SÓ QUE, dentro do seu objeto C1, vc tem uma variavel de instancia q utiliza de um wrapper…entao, assim como vc está deixando o C1 para o GC, vc tb está deixando a referencia do wrapper, SHORT

ok!?

Ué, e C3 não está null tbém?

Engraçado que eu colocaria a C(2) tbém de cara, mas por achar que C1 e C3 estão null.

Deiverson

marcioa1:
pardal_nb:
o livro esta certo…

existem 2 objetos…

vc acertou q o C1 está sujeito ao coletor, SÓ QUE, dentro do seu objeto C1, vc tem uma variavel de instancia q utiliza de um wrapper…entao, assim como vc está deixando o C1 para o GC, vc tb está deixando a referencia do wrapper, SHORT

ok!?

???

Qual o nome desta referência do wrapper ? O que é referÊncia do wapper ? Quem é o wapper ? :oops:

???
Márcio

hehehehe, tambem “viajei” :stuck_out_tongue:

P

Vamos lá...

C3 não é NULO.... C3 faz referecia a C2...reparem que o metodo retorno uma referencia para o objeto q eh passado, q neste caso é :

CardBoard go(CardBoard cb) {  
         cb = null;  
         return cb;  
     }  

CardBoard c3 = c1.go(c2);

C2... Por isso C3 nao eh nulo, ok?!

Seguindo...

Wrapper é um empacotador de tipos primitivos...faz com q tipos primitivos (int, flot, double ...) se tornem OBJETOS(Float, Integer ...)...

Na linha 2:
Short story = 5;
Temos uma variável de instância, ou seja do objeto instanciado...qnd nós instanciamos C1 (CardBoard c1 = new CardBoard(); ) ele terá essa variável de instancia com ele...isto é, "story" É uma var. de instancia de C1...e variaveis de instancia estão sujeitas ao GC....ok?!

seguindo..

qnd nós atribuimos um valor NULL para C1, ou seja, qnd tiramos o "controle remoto", o ponteiro, para o objeto no HEAP, nós estamos deixando para trás tb o nosso objeto story...(story é um objeto, e nao um tipo primitivo, notem, Short....se fosse short, ai a resposta seria 1)

certo pessoal?! :D

dreamspeaker
pardal_nb:
Vamos lá...

C3 não é NULO.... C3 faz referecia a C2...reparem que o metodo retorno uma referencia para o objeto q eh passado, q neste caso é :

CardBoard go(CardBoard cb) {  
         cb = null;  
         return cb;  
     }  

CardBoard c3 = c1.go(c2);

C2... Por isso C3 nao eh nulo, ok?!

E como se explica isso?
class CardBoard {  
        Short story = 5;  
        CardBoard go(CardBoard cb) {  
            cb = null;  
            return cb;  
        }  
        public static void main(String[] args) {  
           CardBoard c1 = new CardBoard();  
           CardBoard c2 = new CardBoard();  
           CardBoard c3 = c1.go(c2);  
           c1 = null;  
           
           System.out.println(c1==null); // true
           System.out.println(c2==null); // false
           System.out.println(c3==null); // TRUE -> C3 É NULO
           // do Stuff  
       }  
   }
felipealbuquerque

Pardal, tente entender essa lógica:

  1. CardBoard.story é uma variável de instância, isso é correto. Mas repare que a a pergunta refere-se à quantidade de objetos que são elegíveis para o GC;
  2. CardBoard.story não é um objeto, é uma variável de referência, portanto, no caso, aponta para um objeto do tipo Short;
  3. Duas variáveis de referência dos tipos abaixo sempre apontarão para o mesmo objeto (para economia de memória):
    3.1 Byte
    3.2 Boolean
    3.3 Character (de \u0000 a \u007F)
    3.4 Short e Integer (de -128 a 127)
  4. Temos dois objetos CardBoard criados. Os dois têm variáveis story que apontam para o mesmo objeto Short com valor 5;
  5. Quando o CardBoard referenciado por c1 for coletado, a variável desse objeto story perderá sua referência com o Short, mas a variável story do objeto CardBoard referenciado por c2 ainda não perdeu sua referência, portanto esse Short não é elegível para o GC!!!
  6. Se o código fosse como o descrito abaixo, realmente seriam dois objetos elegíveis para o GC:
class CardBoard {

    /*
     * story é maior que 127, portanto cada story de cada objeto CardBoard 
     * criado referenciará um objeto diferente!!!
     */
    Short story = 1680;
    CardBoard go(CardBoard cb) {
        cb = null;
        return cb;
    }
    public static void main(String[] args) {
        CardBoard c1 = new CardBoard();
        CardBoard c2 = new CardBoard();
        CardBoard c3 = c1.go(c2);
        c1 = null;
        // do Stuff
    }
}
felipealbuquerque
dreamspeaker:
pardal_nb:
Vamos lá...

C3 não é NULO.... C3 faz referecia a C2...reparem que o metodo retorno uma referencia para o objeto q eh passado, q neste caso é :

CardBoard go(CardBoard cb) {  
         cb = null;  
         return cb;  
     }  

CardBoard c3 = c1.go(c2);

C2... Por isso C3 nao eh nulo, ok?!

E como se explica isso?
class CardBoard {  
        Short story = 5;  
        CardBoard go(CardBoard cb) {  
            cb = null;  
            return cb;  
        }  
        public static void main(String[] args) {  
           CardBoard c1 = new CardBoard();  
           CardBoard c2 = new CardBoard();  
           CardBoard c3 = c1.go(c2);  
           c1 = null;  
           
           System.out.println(c1==null); // true
           System.out.println(c2==null); // false
           System.out.println(c3==null); // TRUE -> C3 É NULO
           // do Stuff  
       }  
   }

c3 é nulo! O método CardBoard.go(CardBoard) retorna uma variável de referência que não aponta para nada (nula)!
c2 não é nulo porque o que é passado para o método é uma cópia de como chegar ao objeto referenciado por ele, portanto o valor de c2 (como chegar no objeto) continua inalterado, independente do que acontecer no método! O método, todavia, pode modificar o objeto.

P
felipealbuquerque:
2. CardBoard.story não é um objeto, é uma variável de referência, portanto, no caso, aponta para um objeto do tipo Short; 6. Se o código fosse como o descrito abaixo, realmente seriam dois objetos elegíveis para o GC:
class CardBoard {

    /*
     * story é maior que 127, portanto cada story de cada objeto CardBoard 
     * criado referenciará um objeto diferente!!!
     */
    Short story = 1680;
    CardBoard go(CardBoard cb) {
        cb = null;
        return cb;
    }
    public static void main(String[] args) {
        CardBoard c1 = new CardBoard();
        CardBoard c2 = new CardBoard();
        CardBoard c3 = c1.go(c2);
        c1 = null;
        // do Stuff
    }
}

entao me fala, quais?

se for como estão falando seriam os mesmos objetos :?

felipealbuquerque
pardal_nb:
felipealbuquerque:
2. CardBoard.story não é um objeto, é uma variável de referência, portanto, no caso, aponta para um objeto do tipo Short; 6. Se o código fosse como o descrito abaixo, realmente seriam dois objetos elegíveis para o GC:
class CardBoard {

    /*
     * story é maior que 127, portanto cada story de cada objeto CardBoard 
     * criado referenciará um objeto diferente!!!
     */
    Short story = 1680;
    CardBoard go(CardBoard cb) {
        cb = null;
        return cb;
    }
    public static void main(String[] args) {
        CardBoard c1 = new CardBoard();
        CardBoard c2 = new CardBoard();
        CardBoard c3 = c1.go(c2);
        c1 = null;
        // do Stuff
    }
}

entao me fala, quais?

se for como estão falando seriam os mesmos objetos :?

O CardBoard referenciado por c1 e o Short (de valor 1680) referenciado por c1.story.

Novamente: quando o Short está entre -128 e 127, duas variáveis de referência apontam para o mesmo objeto. Fora desse intervalo, vários objetos são criados.

P

e o C3?!

ele continua a msm coisa, entao seriam 3 objetos, nao 2, certo?!

felipealbuquerque

pardal_nb:
e o C3?!

ele continua a msm coisa, entao seriam 3 objetos, nao 2, certo?!

Em momento algum foi criado um objeto para c3 referenciar. Note que, desde sua inicialização, c3 == null.
Um erro que costumam-se cometer é confundir as variáveis de referência com os objetos em si (e isso é explorado no exame). Quando declaramos uma variável de referência, não necessariamente criamos um objeto junto.

P

agora q nao estou entendo mais nada entao…

falaram q C3 e C1 sao nulos e q estao a disposicao do GC…

qual a resposta da pergunta no livro??
2, story e C1 ??

e qual a resposta para o exemplo q vc deu?

felipealbuquerque

c1 e c3 não são objetos! São apenas variáveis de referência.

Não é porque c1 e c3 são nulos que haverão necessariamente dois objetos disponíveis para o GC.

Siga a lógica do meu primeiro post que você conseguirá visualizar o porquê de a resposta correta ser somente um objeto (o CardBoard que era referenciado por c1), no exercício do livro.
No livro, erroneamente, a resposta é a © - 2 objetos (o referenciado por c1 e o Short referenciado pela variável story desse objeto)

No exemplo que eu dei com o Short maior que 127, seriam dois objetos: o CardBoard que era referenciado por c1 e o Short referenciado pela variável story desse CardBoard.

P

entendi o q vc quis dizer.

Se a linha 4 fosse comentada:

class CardBoard {
    Short story = 5;
    CardBoard go(CardBoard cb) {
        cb = null;
        return cb;
    }
    public static void main(String[] args) {
        CardBoard c1 = new CardBoard();
        CardBoard c2 = new CardBoard();
        CardBoard c3 = c1.go(c2);
        c1 = null;
        c2 = null;
        // do Stuff
    }
}

teríamos 2 objetos (C1 e C3), certo?

Guilherme_Gomes

Li tudo que escreveram nesse tópico, e entendi bem.

Isso que o felipe falou fez bastante sentido,

Só não quero que pare por aqui, quero saber se realemente está errado no livro ou não ^^

Obrigado,

felipealbuquerque

pardal_nb:
entendi o q vc quis dizer.

Se a linha 4 fosse comentada:

class CardBoard {
    Short story = 5;
    CardBoard go(CardBoard cb) {
        cb = null;
        return cb;
    }
    public static void main(String[] args) {
        CardBoard c1 = new CardBoard();
        CardBoard c2 = new CardBoard();
        CardBoard c3 = c1.go(c2);
        c1 = null;
        c2 = null;
        // do Stuff
    }
}

teríamos 2 objetos (C1 e C3), certo?

  • Até a linha 9, teremos c1 referenciando um CardBoard, c2 referenciando outro e suas respectivas variáveis story apontando para o mesmo Short;
  • Na linha 10, teremos c3 referenciando o mesmo CardBoard que c2;
  • Na linha 11, o objeto que era referenciado por c1 não tem mais nenhuma referência, então fica elegível para o GC;
  • O código do livro vai até aí, então, mesmo com a linha 4 comentada, teríamos apenas um objeto elegível para o GC;
  • Com a adição da linha 12, teremos… apenas um objeto elegível para o GC! Note que c2 não referencia mais nada, mais c3, que referenciava o mesmo objeto que c2, ainda o referencia.
  • Se a linha 4 não fosse comentada, c3 não referenciaria nada desde o início, então teríamos 3 objetos elegíveis para o GC: Os CardBoards para os quais c1 e c2 apontavam e, finalmente, o Short com valor 5.
P

certo…

acho q fiquei um cado bitolado…e confundi - como vc disse - variaveis de referencia com objetos…

felipealbuquerque

pardal_nb:
certo…

acho q fiquei um cado bitolado…e confundi - como vc disse - variaveis de referencia com objetos…

Esse assunto realmente costuma gerar confusões… deve ser um dos prediletos dos elaboradores do exame. :-o

danielbussade

Fala galera blz. li o tópico e tbm fiquei com uma dúvida , olhando este código:

class CardBoard {

    public static void main(String[] args) {
        CardBoard c1 = new CardBoard();
        CardBoard c2 = new CardBoard();
        CardBoard c3 = null;
        CardBoard cb=c2; 
        System.out.println("Cb=" + cb);
        System.out.println("C2=" + c2);
        c1 = null;
        cb=null;
        System.out.println("Depois que cb recebe null");
        System.out.println("Cb=" + cb);
        System.out.println("C2=" + c2);
        System.out.println("C1=" + (c1==null));
        System.out.println("C2=" + (c2==null));
        System.out.println("C3= "+ (c3==null));
        System.out.println("Cb= "+ (cb==null));  
    }
}

A minha dúvida é a seguinte quando faço cb=c2, significa que cb aponta para o mesmo objeto que c2 certo?? Agora então quando atribui cb=null, e se eles estão apontando para o mesmo objeto, porque tbm o c2 nao ficou null??

Att

J

danielbussade:
Fala galera blz. li o tópico e tbm fiquei com uma dúvida , olhando este código:

class CardBoard {

    public static void main(String[] args) {
        CardBoard c1 = new CardBoard();
        CardBoard c2 = new CardBoard();
        CardBoard c3 = null;
        CardBoard cb=c2; 
        System.out.println("Cb=" + cb);
        System.out.println("C2=" + c2);
        c1 = null;
        cb=null;
        System.out.println("Depois que cb recebe null");
        System.out.println("Cb=" + cb);
        System.out.println("C2=" + c2);
        System.out.println("C1=" + (c1==null));
        System.out.println("C2=" + (c2==null));
        System.out.println("C3= "+ (c3==null));
        System.out.println("Cb= "+ (cb==null));  
    }
}

A minha dúvida é a seguinte quando faço cb=c2, significa que cb aponta para o mesmo objeto que c2 certo?? Agora então quando atribui cb=null, e se eles estão apontando para o mesmo objeto, porque tbm o c2 nao ficou null??

Att

O que vc fez foi anular a referência cb, o objeto ainda existe e continua sendo referenciado por c2, ou seja, vc tinha duas referências para um único objeto e anulou uma delas, a outra continua apontando para o objeto.

felipealbuquerque

Exato. Pessoal, não podemos confundir referências com objetos! Apesar de serem termos relacionados, são distintos.

Andre_Brito

Qual livro é esse?
Use a cabeça java? Eu tenho e não consigui achar… aliás, achei alguns erros só no primeiro capítulo do livro…

P

dedejava:
Qual livro é esse?
Use a cabeça java? Eu tenho e não consigui achar… aliás, achei alguns erros só no primeiro capítulo do livro…

é o livro guia para a certificação da Kath e Bert

felipealbuquerque

pardal_nb:
dedejava:
Qual livro é esse?
Use a cabeça java? Eu tenho e não consigui achar… aliás, achei alguns erros só no primeiro capítulo do livro…

é o livro guia para a certificação da Kath e Bert

Complementando: SCJP versão 5

felipealbuquerque

Errata da editora (pode ser visualizada através desse link):

Ou seja, o valor de CardBoard.story é 200, não 5. Com esse valor, a resposta C (2) é a correta.

Caso resolvido! :smiley:

Andre_Brito

Nossa… eu comprei o use a cabeça Java achando que era esse pra certificação :frowning:
Até estranhei por estar achando meio fácil demais o livro :frowning:

Criado 13 de dezembro de 2007
Ultima resposta 17 de dez. de 2007
Respostas 29
Participantes 10