# Strange Error Regarding Lists and Variables

• 03-29-2011, 02:39 PM
GuiRitter
Strange Error Regarding Lists and Variables
Hi all.

It's my fourth day at my Java class at university and I stumbled upon an error that not even my teacher have been able to solve. Here's the code:

Code:

``` // start of Cobaias.java package ex2; import java.math.BigDecimal; import java.math.BigInteger; public class Cobaias {     private BigDecimal ncobaia = new BigDecimal("0");     private BigDecimal tcobaia = new BigDecimal("0");     public void ncobaia(BigDecimal p){ ncobaia = p; }     public BigDecimal ncobaia(){ return ncobaia; }     public void tcobaia(BigDecimal p){ tcobaia = p; }     public BigDecimal tcobaia(){ return tcobaia; } } // end of Cobaias.java // start of Main.java package ex2; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import javax.swing.JOptionPane; public class Main {     private List lista = new ArrayList();     private Cobaias cobaia = new Cobaias(); // = (Cobaias) lista.get(0);     private BigDecimal totalx = new BigDecimal("0");     private BigDecimal totalc = new BigDecimal("0");     private BigDecimal totalr = new BigDecimal("0");     private BigDecimal porctc = new BigDecimal("0");     private BigDecimal porctr = new BigDecimal("0");     public Main(){         leitura();         cálculo();         exibição();     }     public static void main(String[] args) {         new Main();     }     public void leitura(){         for(int fx = 0; fx < 2; fx++){             cobaia.ncobaia(new BigDecimal(JOptionPane.showInputDialog("E" + (fx+1) + ": Digite a quantidade de cobaias utilizadas na experiência:")));             cobaia.tcobaia(new BigDecimal(JOptionPane.showInputDialog("E" + (fx+1) + ": Digite 1 se utilizou coelhos e 2 se utilizou ratos:")));             lista.add(fx,cobaia);         } // tag 1     }     public void cálculo(){         for(int fx = 0; fx < 2; fx++){             cobaia = (Cobaias) lista.get(fx); // tag 2             totalx = totalx.add(cobaia.ncobaia());             if(cobaia.tcobaia().compareTo(new BigDecimal("1")) == 0){                 totalc = totalc.add(cobaia.ncobaia());             }else if(cobaia.tcobaia().compareTo(new BigDecimal("2")) == 0){                 totalr = totalr.add(cobaia.ncobaia());             }         }         porctc = totalc.multiply(new BigDecimal("100")).divide(totalx);         porctr = totalr.multiply(new BigDecimal("100")).divide(totalx);     }     public void exibição(){         String print = "";         print += "Total de cobaias utilizadas: " + totalx + "\n\n";         print += "Total de coelhos utilizados: " + totalc + "\n";         print += "Total de ratos utilizados: " + totalr + "\n";         print += "Porcentagem de coelhos utilizados: " + porctc + "%\n";         print += "Porcentagem de ratos utilizados: " + porctr + "%";         JOptionPane.showMessageDialog(null, print);     } } // end of Main.java```
At the commentary "tag 1", if I print "tcobaia" from the object "cobaia", which have received the value directly, I'll get the right value. But at "tag 2", if I print "tcobaia" from the object "cobaia", which have received the object from the list, all "tcobaia" will have the same value as the last one.

What's wrong?

(If you have trouble understanding the error, "compile" the code. I use NetBeans.)
• 03-29-2011, 08:41 PM
Zack
Alright, so... I'm not sure how far into Java programming you are, so I'll try to make this simple.

When you declare this variable:
private Cobaias cobaia = new Cobaias();
...then you declare it for the entire class. It becomes a global object to everything in that class. This means that in the loop indicated by "tag 1", you are editing the same object twice.

In some languages, this would be fine; however, in Java, everything is passed by reference; that means that, even though the "cobaia" has been passed to the array, calling those methods on it still modifies it.

The solution to this issue is rather simple; you must re-declare a NEW cobaia object for each iteration of the loop. Such as:
Code:

```    public void leitura(){         for(int fx = 0; fx < 2; fx++){             [color=red]Cobaias cobaia = new Cobaias();[/color]             cobaia.ncobaia(new BigDecimal(JOptionPane.showInputDialog("E" + (fx+1) + ": Digite a quantidade de cobaias utilizadas na experiência:")));             cobaia.tcobaia(new BigDecimal(JOptionPane.showInputDialog("E" + (fx+1) + ": Digite 1 se utilizou coelhos e 2 se utilizou ratos:")));             lista.add(fx,cobaia);         } // tag 1     }```

And you will also need to add a similar line in your second method:
Code:

```    public void cálculo(){         [color=red]Cobaias cobaia = null; // null because we don't have a reference... yet![/color]         for(int fx = 0; fx < 2; fx++){             cobaia = (Cobaias) lista.get(fx); // tag 2             totalx = totalx.add(cobaia.ncobaia());             if(cobaia.tcobaia().compareTo(new BigDecimal("1")) == 0){                 totalc = totalc.add(cobaia.ncobaia());             }else if(cobaia.tcobaia().compareTo(new BigDecimal("2")) == 0){                 totalr = totalr.add(cobaia.ncobaia());             }         }         porctc = totalc.multiply(new BigDecimal("100")).divide(totalx);         porctr = totalr.multiply(new BigDecimal("100")).divide(totalx);     }```

And lastly, you must remove the declaration that you already have (private Cobaias cobaia = new Cobaias();).

Hope that makes sense!
• 03-29-2011, 08:47 PM
GuiRitter
I completely understood the first alteration. My knowledge on pointers in C++ helped a lot.

But for the second one, I didn't understood why
Code:

`Cobaias cobaia = null;`
is out of the for loop.

But thanks for the help already!
• 03-29-2011, 10:00 PM
Zack
Quote:

Originally Posted by GuiRitter
But for the second one, I didn't understood why
Code:

`Cobaias cobaia = null;`
is out of the for loop.

Actually, it can be inside as well. That's just a force of habit from doing it most efficiently; reassigning the value twice isn't strictly necessary, as you would do if you did this:
Code:

```// Inside the for loop: Cobaias cobaia = null; // Done each time; but not necessary cobaia = (Cobaias) lista.get(fx);```

You could also do this inside the for loop:
Code:

`Cobaias cobaia = (Cobaias) lista.get(fx);`
...and omit the = null altogether.

All three work, it's up to you which you use. Good luck!
• 03-29-2011, 10:03 PM
Fubarable
I agree with all that Zack has said but have another unrelated question: Why are you using BigDecimals here? Isn't that a bit of overkill since ints and doubles would suffice nicely?
• 03-29-2011, 10:33 PM
GuiRitter
Quote:

Originally Posted by Zack
Good luck!

Thanks!

Quote:

Originally Posted by Fubarable
I agree with all that Zack has said but have another unrelated question: Why are you using BigDecimals here? Isn't that a bit of overkill since ints and doubles would suffice nicely?

I've had many unhappy episodes in C/C++ because of the way floats work so I just prefer to use arbitrary precision arithmetic.
• 03-29-2011, 10:36 PM
Fubarable
Quote:

Originally Posted by GuiRitter
I've had many unhappy episodes in C/C++ because of the way floats work so I just prefer to use arbitrary precision arithmetic.

It's definitely overkill here. I urge you to use ints for your int input, doubles for your non-financial double inputs, and enums for your constants.