2

I am attempting to give a void function to a Tree. It calculates some parameters and uses Ids to reference some coordinates and the distance between them. The problem I have is that every recursion call returns me 0 on both parameters I use, I thought in Java every variable was a reference so this would work, but I seem to be missing something. Here is the code:

public void volumeandcost(Integer  volume,Float cost){
    if(children().equals(0)){//children() returns the number of children our tree has
        volume=volume+getCapacidad(this.root);//root is the Id
    }
    else{//recursive call
        ArrayList<Integer> myvol= new ArrayList();
        ArrayList<Float> mycost=new ArrayList();
        for(int i=0;i<this.children();i++){
            myvol.add(new Integer(0));
            mycost.add(new Float(0.0));                
            children.get(i).volumeandcost(myvol.get(i), mycost.get(i));
            cost=cost+mycost.get(i)+myvol.get(i)*
                  square(ProbIA5Board.m_dist.get(this.root).get(this.children.get(i).getId()));
        }
        //this calculates our volume in case we have children
        volume=min(getCapacidad(root)*3,mysum(myvol)+getCapacidad(root));
    }
}

I call this function with both parameters initially set at 0, and they come back in the same way after the call to volumeandcost.

After following some advice I implemented a new class Pair like this:

public class Pair {
Integer vol;Float cost;
public Pair (){this.vol=new Integer(0);this.cost=new Float(0);}
Integer getVol(){ return this.vol;}
Float getCost(){ return this.cost;}
void setVol(Integer x){this.vol=x ;}
void setCost(Float x){this.cost=x ;}
void addVol(Integer x){this.vol=this.vol+x;}
    void addCost(Float x){this.cost=this.cost+x;}
}

and modified the function so that it's like this:

    public void volumeandcostp(Pair p){
    if(children().equals(0)){
        p.setVol(p.getVol() + getCapacidad(this.root));//tenemos el volumen
    }
    else{//recursion
        ArrayList<Pair> myvol= new ArrayList();
        for(int i=0;i<this.children();i++){
            myvol.add(new Pair());                
            children.get(i).volumeandcostp(myvol.get(i));
            myvol.get(i).getCost());
            p.addCost(myvol.get(i).getCost()+ myvol.get(i).getVol()*                            square(ProbIA5Board.m_dist.get(this.root).get(this.children.get(i).getId())));
        }              p.setVol(min(getCapacidad(root)*3,mysump(myvol)+getCapacidad(root)));
    }   
}

But all the getters from Pair keep giving me 0 as answer.

  • But `volume` and `cost` are **parameters**. In Java they don't work bidirectional... Java works with *call-by-value*. – Willem Van Onsem Mar 30 '17 at 18:58
  • https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value As your parameters are actually passed by value, you only change the local copies. – Roman Puchkovskiy Mar 30 '17 at 19:00

2 Answers2

1

I thought in Java every variable was a reference.

First of all that statement is wrong: you have primitive types like int, float, char. Those are not references to begin with. But indeed variables with types other than those eight are references.

But when you call a function, Java does a call-by-value. That means the references are copied. When you call: volumeandcost(a,b). Java will make a copy of the reference. So volume and cost work independently. Setting them (i.e. assigning a new value to them) in your method has no effect.

You can alter the state of the objects you are given: since you copy the reference a refers to the same object as volume (in the example above), you can call methods on the objects the references refer to and alter the state, but you cannot change the reference itself.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
1

As provided in other answers, you can only alter the state of the objects when you pass them to a method- Java is call by value. Consider this instead of Integers :

List<Integer> list = new ArrayList<Integer>();
System.out.println( "Before adding size is " + list.size() );
modifyList(list);
System.out.println( "After adding size is " + list.size() ); 

public void modifyList( List<Integer> list )
{
   list.add( 5 );
}

Why do you see the list.size() modified ? Because list's state is modified not the original reference to list itself, the copied reference that passed to method played with a method called add and modified the state of object it refers to. So when you call size() using original reference , you will get the updated state of the object.

Now, to tackle your problem, you could do it with devising your own class, some thing like :

class Metrics
{
   Integer volume;
   Float cost;
}

Pass Metrics to your new method and update the fields volume, cost inside your method.

SomeDude
  • 13,876
  • 5
  • 21
  • 44