Eu estava resolvendo os exercícios do capítulo 3 (Assignments) e, logo no exercício 2, me deparei com a seguinte questão:
[quote]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.[/quote]
Seguindo o meu raciocínio (segundo a seqüência do código):
Um objeto CardBoard é criado e referenciado por c1. A variável de referência story aponta para um objeto Short de valor 5;
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
O método go(CardBoard) é chamado, com uma cópia da variável de referência c2;
c2, portanto, continua apontando para o mesmo CardBoard;
c3 não aponta para nenhum objeto;
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;
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!
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.
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
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!?[/quote]
???
Qual o nome desta referência do wrapper ? O que é referÊncia do wapper ? Quem é o wapper ? :oops:
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!?[/quote]
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.
[quote=marcioa1][quote=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!?[/quote]
???
Qual o nome desta referência do wrapper ? O que é referÊncia do wapper ? Quem é o wapper ? :oops:
Wrapper é um empacotador de tipos primitivos…faz com q tipos primitivos (int, flot, double …) se tornem OBJETOS(Float, Integer …)…
Na linha 2:
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)
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;
CardBoard.story não é um objeto, é uma variável de referência, portanto, no caso, aponta para um objeto do tipo Short;
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)
Temos dois objetos CardBoard criados. Os dois têm variáveis story que apontam para o mesmo objeto Short com valor 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!!!
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
}
}
[code]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
}
} [/code][/quote]
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.
[quote=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:
[code]
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
}
}
[/code][/quote]
entao me fala, quais?
se for como estão falando seriam os mesmos objetos :?
[quote=pardal_nb][quote=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:
[code]
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
}
}
[/code][/quote]
entao me fala, quais?
se for como estão falando seriam os mesmos objetos :?
[/quote]
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.
ele continua a msm coisa, entao seriam 3 objetos, nao 2, certo?![/quote]
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.
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.
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?[/quote]
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.