Java e Ponteiros

Probleminha, galera!

Suponham que eu tenho essas 3 classes:

(Código 1)

public class Pacote implements Serializable{
   
   static final String serialVersionId = "blablabla1";
   
   int id;
   List<Item> itens;
   //... gets e sets ...
}

public class Item implements Serializable{
   
   static final String serialVersionId = "blablabla2";
   
   int id;
   Pacote pacote;
   List<ItemHistorico> historico;
   //... gets e sets ...
}

public class ItemHistorico implements Serializable{
   
   static final String serialVersionId = "blablabla3";
   
   int id;
   String nome;
   Item item;
   //... gets e sets ...
}

A seguir apresento este código:
(Código 2)

public static void montarItensHistoricos(List<Item> itens){
   
   Item item;
   ItemHistorico itemHistorico;
   
   for(int i = 0; i < itens.size(); i++){
      
      item = itens.get(i);
      
      itemHistorico = new ItemHistorico();
      itemHistorico.setNome("exemplo " + i);
      itemHistorico.setItem(item);
      
      item.setHistorico(new ArrayList<ItemHistorico>());
      item.getHistorico().add(itemHistorico);
   }
}

O que eu espero como resultado final deste código é o seguinte, após uma iteração de 2 itens:

No entanto o que eu obtenho é este resultado:

A causa disso eu mesmo posso lhes dizer.

(Como Java utiliza ponteiros implicitamente, buscarei abordar o problema orientando o caso ao uso de ponteiros)

Ao realizar o Código2, supondo a iteração daqueles 2 itens, eu tenho a lista de itens, e tenho um ponteiro “item”, que apontará para cada item durante cada uma das repetições, certo? Então, na primeira repetição, o ponteiro “item” está apontando para o primeiro item da lista “itens”, e em dado momento realiza esta operação: “itemHistorico.setItem(item);”. Ao fazer isto, estamos dizendo ao Java que o ponteiro pra Item que há dentro do objeto “itemHistórico” vai apontar para onde também aponta o ponteiro “item” (é confuso, mas pra quem tá acostumado com ponteiros, é só ler umas 3 vezes que dá pra entender :roll: ).

Na segunda repetição da iteração no Código 2, o ponteiro “item” vai apontar para o elemento seguinte na lista “itens”. Quando o ponteiro “item” passar a apontar para este elemento, aquele objeto “itemHistorico” também terá seu apontador de item apontando pra lá, pois a atribuição de objetos em Java é feita por referência.

Alguém sabe como eu posso fazer para obter o primeiro resultado mencionado?

Uma nota importante é o seguinte: eu não quero criar um novo objeto item dentro de itemHistorico para copiá-lo por valor. O que eu quero é referenciar os itens da lista “itens”, e que cada itemHistorico esteja referenciando seu item correspondente na iteração.

Ok, essa foi uma pergunta completamente C++ no forum de java… :lol:

Todo objeto em java é passado por referência, sem exceção. Os tipos primitivos são os únicos que recebem cópias por valor.

Seu código está me parecendo correto. Você tem certeza que o conteúdo da sua lista de itens está correto quando você chama o método?

O problema esta na logica que vc esta usando.

A cada iteração vc esta trocando a lista e não adicionando novas informações. Isto ocorre quando vc faz:

item.setHistorico(new ArrayList<ItemHistorico>());

Esperimenta trocar por:

if ( item.getHistorico() == null ){
    item.setHistorico(new ArrayList<ItemHistorico>());
}

Ou seja se o item já tem histórico apenas serão adicionadas informações.

[quote=Andre.flu]O problema esta na logica que vc esta usando.

A cada iteração vc esta trocando a lista e não adicionando novas informações. Isto ocorre quando vc faz:

item.setHistorico(new ArrayList<ItemHistorico>());

Experimenta trocar por:

if ( item.getHistorico() == null ){
    item.setHistorico(new ArrayList<ItemHistorico>());
}

Ou seja se o item já tem histórico apenas serão adicionadas informações.[/quote]

Não vejo onde isso possa resolver o problema… E se ele quiser sempre redefinir a lista? Até porque, a cada iteração ele faz isso para um item diferente… Certamente, não é isso que está causando o comportamento descrito pelo colega…

Nem todos os objetos são passados por referência. A exemplo, tente passar um objeto de String, Integer, Double, ou qualquer objeto de alguma classe em java.lang. Eu não sei ao certo o nome que se dá para essa passagem, mas se você passa um objeto desses para dentro de um método qualquer, e modifica um valor num desses objetos, essa modificação não reflete no objeto que está fora do método.

Tenho certeza sim, debuguei direitinho e infelizmente a lista está correta, antes estivesse errada. :frowning:

Bem, não existe passagem por referência em Java.

Mesmo que uma variável de referência seja uma referência a um objeto, é seu VALOR que é a referência, sendo assim não há passagem por referência e sim por valor.

Exemplo: Você consegue incrementar a referência (o valor da mesma) de um objeto Java como em C++ (onde a referência pode ser obtida de qualquer tipo)?

Não sou expert no assunto e é um pouco difícil conseguir explicar isso, mas é mais ou menos o que eu falei.

Até mais!

ViniGodoy, aquele item.setHistorico(new ArrayList()); está certo ali daquele jeito, sim. Pra cada item que ele percorre, eu quero que ele crie uma lista nova de historico, e quero que ele adicione apenas um objeto nessa lista, que será o objeto itemHistorico que ele está montando durante a iteração.

[quote=Logan-san]
Nem todos os objetos são passados por referência. A exemplo, tente passar um objeto de String, Integer, Double, ou qualquer objeto de alguma classe em java.lang. Eu não sei ao certo o nome que se dá para essa passagem, mas se você passa um objeto desses para dentro de um método qualquer, e modifica um valor num desses objetos, essa modificação não reflete no objeto que está fora do método. [/quote]

Você se engana. Esses objetos são passados por referência sim. Mas são imutáveis. Entenda o seguinte, embora todos os objetos sejam passados por referência no Java, o ponteiro em si é passado por valor.

ViniGodoy

Como posso ter um histórico em que as informações anteriores são apagandas.

Com aquela verificação ele tem o resultado esperado.

Isso acontece porque essas classes geram objetos que são imutáveis, ou seja, mesmo que você tenha a referência aos mesmos, o objeto o qual a refernecia “aponta” nunca é alterado. Se for forçado a “mudanca” do um objeto desses tipos, é criado um novo objeto com o valor novo e a nova referência é utilizada.

[quote=davidbuzatto]
Bem, não existe passagem por referência em Java.

Mesmo que uma variável de referência seja uma referência a um objeto, é seu VALOR que é a referência, sendo assim não há passagem por referência e sim por valor.

Exemplo: Você consegue incrementar a referência (o valor da mesma) de um objeto Java como em C++ (onde a referência pode ser obtida de qualquer tipo)?

Não sou expert no assunto e é um pouco difícil conseguir explicar isso, mas é mais ou menos o que eu falei.

Até mais![/quote]

Essa realmente é uma outra forma de se entender. Tudo em java é passado por valor. Mas todos os objetos são referênciados por ponteiros, que também serão passados por valor. Portanto, você até pode alterar o valor de um objeto num método, mas não o valor do ponteiro que o referencia. Alterações desse tipo estarão restritas ao método, e não mais alterarão o ponteiro original.

Isso que eu falei :smiley:

Sim, estava concordando com você. :slight_smile:
Na verdade, o complicado é tentar explicar java com vocabulário C++.

O ideal é fazer o seguinte:

Java não é C++.
Procure não falar em ponteiros ou referências. Quando você chama uma função, você passa um objeto inteiro para essa função.

A variável que referencia esse objeto é copiada e não poderá ser alterada.

Você pode colocar aí as classes Item e ItemHistorico em anexo para a gente dar uma olhada? Teu código está parecendo certinho, o erro deve estar em outro lugar!

Entendi o seu ponto, ViniGodoy.

Mas voltando… o problema não se trata de quantos elementos a lista de ItemHistorico tenha. Eu quero que aquele método CRIE uma lista nova, independente de, e quero que adicione apenas 1 elemento nela, que no caso é o itemHistorico que ele monta em cada repetição da iteração.

O problema é que pra todos os itemHistorico que ele montar e jogar numa lista de historico dentro do item, ele vai referenciar o último item da lista de itens que está sendo iterada, e esse é o resultado que eu NÃO desejo. O que eu desejo é que ele relacione cada itemHistorico de cada repetição ao item DAQUELA repetição.

O problema ocorre porque o objeto “item” fica apontando pra cada elemento da lista “itens”, e conforme a iteração corre, o lugar pra onde ele tá apontando muda, e com isso todos os itemHistorico que são criados ficam apontando pro mesmo lugar que o objeto “item” aponta, e no fim da iteração o “item” aponta pro último elemento da lista “itens”, e, conseqüentemente, então, todos os “itemHistorico” criados vão referenciar o último “item” na lista “itens” (está muito confuso, eu sei). Esse é o problema que eu quero evitar, percebem?

Tá na primeira mensagem! :stuck_out_tongue:

Logan-san

Deixa eu enteder melhor o que quer:

vc quer que a cada iteração do metodo montarItensHistoricos
vc adicione um novo item de histórico a uma lista de varios itens?

Se for isso o erro esta na implemantação.
Vc não deve guardar a lista de histórico dentro do item pois só é necessário se vc necessita da lista de histórico do item.

Esta lista de histórico que guardaria todos os históricos de todos os itens deve estar na classe Pacote.

E assim ao adicionar um itemHistorico na lista de itens vc deverá adicionar o mesmo item na lista do Pacote.

Isso que você está descrevendo não pode acontecer em Java.

Veja bem, isso aconteceria se a variável item fosse um ponteiro, e o método setItem recebesse o endereço desse ponteiro.

Mas em java, isso não ocorre. Cada vez que você chama o set, o endereço do item iterado será copiado e o objeto de histórico receberá esse endereço.

Alterar o valor de item posteriormente não deverá alterar o valor que está dentro de itemHistorico.

Se isso está ocorrendo, o problema não está aí. Mas em alguma outra classe, que pode estar usando uma variável estática.

Andre.flu

Não, está correto. Eu vou precisar que o Item tenha uma lista de itens de histórico, sim, pois cada item poderá ser alterado e eu quero registrar essas alterações.

O pacote serve apenas para agrupar itens, não se trata de um problema de modelo.

É um problema de lógica, eu não estou sabendo manipular a iteração de maneira correta, para obter o resultado que eu desejo.

Sua lógica parece correta.

Novamente, tem como postar o código das classes Item e ItemHistorico?