[Resolvido] Collections por referência. É real?

11 respostas
hlegius

Salve pessoal !

Estava lendo o livro Hardcore Java quando o autor afirma que as coleções em Java são por referência, logo não criam cópias dos objetos nela inseridos.
Resolvi fazer um teste com ArrayList, porém, eu adicionei um objeto à coleção, listei o conteúdo da collection, setei nulo o objeto que havia passado ao ArrayList e por fim pedi a listagem dos itens do vetor e: exibiu o conteúdo normal.

Obviamente fiz alguma coisa errada - ou estou interpretando de forma errada ( ? ) o que o autor do livro disse.

Alguém tem algum tipo de informação sobre ?

Abraços !

11 Respostas

dyorgio

Nada de errado cara…

se vc setou :

seuObjeto = null;

vc simplismente setou a referencia na variavel seuObjeto apontando para null.

java não tem ponteiro, logo, la dentro do arraylist existe uma outra “variavel” que aponta para
a mesma referencia do seuObjeto;

se vc setar qualquer uma das duas (arraylist e seuObjeto) para null isso não
modifica em nada a referencia da outra.

Para ter esse comportamento tens que trabalhar com um nivel a mais, por exemplo

class ObjetoEmpacotado {
 Object meuObjeto;
}

// exemplo de uso
ObjetoEmpacotado seuObjeto = new ObjetoEmpacotado();

seuObjeto.meuObjeto = "Uma string como exemplo de objeto";
ArrayList<ObjetoEmpacotado> seuArrayList = new ArrayList<ObjetoEmpacotado>();
seuArrayList.add(seuObjeto);

// aqui vc esta definindo como null o objeto encapsulado dentro da classe.
seuObjeto.meuObjeto = null;

// isso é verdadeiro:
System.out.println(seuObjeto.meuObjeto == seuArrayList.get(0).meuObjeto);

espero que tenha entendido :slight_smile:

davidbuzatto
// instancia SeuTipo e aponta o endereço da instância para inst (cria uma referência)
SeuTipo inst = new SeuTipo();

// instancia uma lista de SeuTipo
List<SeuTipo> lista = new ArrayList<SeuTipo>();

// adiciona (a referência!) da instância "inst" na lista, ou seja, agora contém um item que aponta para o objeto
lista.add(inst);

// aponta inst para null, mas a lista ainda contém a referência para a qual inst apontava originalmente
inst = null;

Em Java TUDO é passado por favor. Não quer dizer que se você modificou uma determinada referência essa modificação será replicada para quem aponta para o mesmo local. Em C++ vc conseguiria amarrar o endereço na coleção e então mudar o ponteiro, mas em Java não.

[]´s

hlegius

Aaah, então eu entendi errado o que o autor do livro tentou explicar. Vou ver se consigo pegar o trecho hoje quando chegar em casa para reler e ver se entendo o que ele quis dizer com referência e não por valor.

Não tem como em Java forçar uma referência ? É sempre por valor e “ponto” ?

Abraços !

dyorgio

O contrario, é sempre por referencia, porem é o valor de uma referencia…

maior_abandonado

hlegius:
Aaah, então eu entendi errado o que o autor do livro tentou explicar. Vou ver se consigo pegar o trecho hoje quando chegar em casa para reler e ver se entendo o que ele quis dizer com referência e não por valor.

Não tem como em Java forçar uma referência ? É sempre por valor e “ponto” ?

Abraços !

eu posso até estar enganado mas… acho que você intendeu corretamente o livro, mas intendeu errado o exemplo no código.

pense no seguinte, quando você da um

new SeuObjeto()

, você cria o objeto na memória, um objeto de verdade, não uma referencia, sempre que você coloca

variavel = objeto;

variavel2 = mesmoObjeto

suaLista.add(objeto)

cada um ai guarda uma referencia para o objeto da memoria, portanto, quando você faz

variavel2 = null

você nulou a referencia variavel2 (sim, ela é uma referencia, e não o objeto), mas ainda existem as outras 2 referencias, se você fizer o mesmo com variavel, ainda vai ter a referencia adicionada na lista, mesmo que você remova da lista ainda vai existir o objeto la na memória até que o garbage colector o remova, apenas as referencias foram perdidas…

pense o seguinte, quando você tem uma variavel de um objeto, essa variavel é a referencia, não o objeto em si, ou seja:

se você da um x = new Objeto();, x aponta para esse objeto ai, se você fizer isso denovo, x vai apontar para um segundo objeto criado em memoria com o new, mas você não mecher no primeiro objeto criado… ai se você depois fizer x = null; você fez x não referenciar mais ninguém, mas os 2 objetos ainda vão estar la na memória, sem você ter mechido…

dyorgio

Apenas para clarificar…

O cara deve estar perguntando : “Ta, mais como eu tiro esse objeto da memoria?”

simples, vc não tira…

O Garbage Collector faz isso pra vc, assim que ele verificar que ninguem mais esta apontando
para esse objeto ele limpa ele da memoria.

ViniGodoy

Ele só quer que você tome o seguinte cuidado:

public class Autor {
    private String nome;

    public String getNome() { return nome; }
    public void setNome(String nome) { this.nome = nome);
}
List<Autor> autores = new ArrayList<Autor>();
Autor autor = new Autor();
autor.setNome("Vinícius");
autores.add(autor); //Adicionei na coleção.

//Vamos alterar o primeiro da coleção
autores.get(0).setNome("Mendonça");

//Vamos imprimir o nome do objeto original:
System.out.println(autor.getNome());

Como você pode ver, o nome do objeto original também mudou. Isso pq, na verdade, tanto a lista quanto a variável autor apontam para o mesmo objeto na memória.

hlegius

maior_abandonado,
Entendi ! Quase fiquei com a ideia errada em mente hahaha =P Já estava dando um nó x)

dyorgio, certo. O GC passa assim que não houver mais referências àquele objeto. Mas seria algo imediato ou ele “roda” de tempos em tempos ?

ViniGodoy, sim, provavelmente ele queria alertar para isso mesmo. Alterando ou removendo alguma coisa da coleção, afetará também o objeto “real”, assim digamos.

Valeu mesmo galera pelas explições detalhadas :slight_smile:

dyorgio

Exitesm 128391872391823 de implementações do GC na JVM…
e ainda cada uma com configurações diversas…
o GC normalmente tem prioridade a baixo da app, e se ele ve que deixando o lixo ali
por digamos 10 minutos não afetara o desempenho da app, tem memoria sobrando por exemplo,
ele não fara a limpeza…pois um GC que faz limpeza direto afeta a performance da app…
porem existem cenarios que tem muita sujeira a ser limpa o tempo todo.
ai vc configura o GC para isso, ou podes usar System.gc();

esse comando não é recomendado, melhor configurar o GC do que pedir pra ele rodar…

e tb na documentação do System.gc() diz que não é garantido que essa chamada faça algo,
as vezes tu chama o GC mais ele soh limpa quando achar que deve :P.

resumindo…em 98,7241% dos casos vc não precisa mecher no GC, essa é a blz da JVM :slight_smile:

hlegius

quote=dyorgioe tb na documentação do System.gc() diz que não é garantido que essa chamada faça algo,
as vezes tu chama o GC mais ele soh limpa quando achar que deve :P. (…)[/quote]

Hahahaha ! Rachei o bico com isso, cara =P
A parada tem vida própria !

Mas certo, entendi !
Agradeço a sua explicação, agora as coisas fazem mais sentido para mim !

Abraços !

ViniGodoy

Fazendo profiling da VM você vai ver que o GC tem duas formas de operação:

a) A limpeza de objetos de vida curta: Que é extremamente rápida e frequente. Muitas vezes a limpeza desses objetos nem sequer envolve desreservar memória, e sim, só usar esse espaço livre para outros objetos.
b) A limpeza de objetos de vida longa: Aqui geralmente o GC faz uma compactação da memória e faz limpeza de fato de memória.

Você também observa que o gc() roda com mais frequência se a memória máxima está próxima de ser atingida. E a limpeza longa quase nunca ocorre quando isso está longe.

O uso de gc tem diversas vantagens sobre linguagens não gerenciadas: Permite que blocos maiores de memória sejam alocados ou desalocados, o que tem impacto direto na performance. Permite o reaproveitamento fácil de áreas de memória, o que torna o custo da criação e destruição dos objetos de vida curta próximo ao zero.

Mas tem desvantagens também: Você nunca sabe exatamente quando o gc vai rodar e quanta memória ele vai liberar. Como ele também trabalhar com uma área de memória própria, ele pode consumir mais espaço do que o mínimo necessário para sua aplicação rodar.

Para mais informações sobre o funcionamento do gc e alocação de memória leia:



http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol23/issue7/spe836.pdf
http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol24/issue6/spe895.pdf

Para saber como funcionará a próxima versão de gc, que entrará no Java 7, leia:
http://research.sun.com/jtech/pubs/04-g1-paper-ismm.pdf

Criado 11 de março de 2010
Ultima resposta 11 de mar. de 2010
Respostas 11
Participantes 5