-2

I'm struggling to fully understand copy-in / copy-out passing in Java. I'm not asking if Java is pass-by-value or pass-by-reference, I'm just having trouble understanding it in this scenario.

I need to update the floats (f1, f2, and f3) in the main method, adjusting the distance using the adjustDistance() method. This is for a homework quiz, so what I can/can't change is limited. Looking for a bit of info as to what I need to do and why.

This is the code:

public class Flow {
public static String formatF1F2F3(float f1, float f2, float f3)
{
    return
      "f1 = " + f1 + ", f2 = " + f2 + ", f3 = " + f3;
}

//      The new record type is needed to
//      so that the two results
//      of adjustDistance can be returned together.
//
//      adjustDistance is a method inside this
//      class so that parameter passing is simpler
private static class TwoFlows
{
    public float flow1;
    public float flow2;

    public TwoFlows(float flow1, float flow2)
    {
        this.flow1 = flow1;
        this.flow2 = flow2;
    }

    public void adjustDistance()
    {
        if ( Math.abs(flow1 - flow2) < 10 )
        {
            if(flow1 > flow2)
            {
                flow2 = flow2 / 3;
                flow1 = flow1 + flow2;
                flow1 = flow1 + flow2;
            }
            else
            {
                flow1 = flow1 / 3;
                flow2 = flow2 + flow1;
                flow2 = flow2 + flow1;
            }
        }
    }
}

public static void main(String[] args)
{
    float f1, f2, f3;
    f1 = 3; f2 = 3; f3 = 4;
    
    System.out.println(formatF1F2F3(f1,f2,f3));

    //    TASK:
    //    Write code that it simulates *copy-in copy-out* passing
    //    of formal parameters flow1 and flow2 to method adjustDistance.
    //    only alter code below this comment

    // my attempt:

    TwoFlows twoFa = new TwoFlows(f2, f3);
    twoFa.adjustDistance();
    System.out.println(formatF1F2F3(f1,f2,f3));
    TwoFlows twoFb = new TwoFlows(f1,f2);
    twoFb.adjustDistance();
    System.out.println(formatF1F2F3(f1,f2,f3));
    TwoFlows twoFc = new TwoFlows(f3,f3);
    twoFc.adjustDistance();
    System.out.println(formatF1F2F3(f1,f2,f3));
} }

OUTPUT:

f1 = 3.0, f2 = 3.0, f3 = 4.0

f1 = 3.0, f2 = 3.0, f3 = 4.0

f1 = 3.0, f2 = 3.0, f3 = 4.0

f1 = 3.0, f2 = 3.0, f3 = 4.0

If I don't initialise new TwoFlows() each time, I get an error. I don't think the flow1 and flow2 update as I'm expecting them to.

The expected output I believe is:

f1 = 3.00, f2 = 3.00, f3 = 4.00

f1 = 3.00, f2 = 1.00, f3 = 6.00

f1 = 3.67, f2 = 0.33, f3 = 6.00

f1 = 3.67, f2 = 0.33, f3 = 10.00

Chelsea
  • 1
  • 3
  • Your 'adjustDistance' method updates the member variables of the TwoFlows object. It has no effect on the similarly-named local variables of main(). Is that what you were expecting? – undefined symbol Jan 31 '23 at 12:37
  • Yes, I think I understand that. The main() method is to change the f1, f2, and f3 variable values using the TwoFlows() and adjustDistance() methods. I'm trying to pass them in a TwoFlows and then adjust the distance, to update the values. – Chelsea Jan 31 '23 at 12:41
  • The fields of `TwoFlows` stay in `TwoFlows`. To print the results, do something like this: `System.out.println(formatF1F2F3(f1,twoFa.flow1,twoFa.flow2));`, etc... – Maurice Perry Jan 31 '23 at 14:04
  • *Yes, I think I understand that.* Let me rephrase - you set main's f1,f2,f3 once at initialization and **there is no code to change their values** and therefore every time you process those same values with formatf1f2f3, you must and will get the same result. – undefined symbol Jan 31 '23 at 23:21

2 Answers2

0

I'm struggling to fully understand copy-in / copy-out passing in Java.

I didn't know the terms copy-in and copy-out but I assume they refer to "pass-by-value". This basically means the value of a parameter or return type is copied, i.e. if you change a variable later this isn't reflected on the other side.

Consider the following:

int someMethod(int param) { 
  try {
        param++;
        return param;
    } finally {
        param--;
        param--;
    }
}

void test() {
  int a = 2; 
  int b = someMethod(a);
}

Here param is a copy of a which means the increment only affects param but not a. When you return param the value is copied to b so the decrement is only applied to param. This means b will have the value 3 while a will keep its value 2 even though param is incremented to 3 first and decremented to 1 after defining the return value. - In your example this means the values of f1, f2 and f3 are copied to TwoFlows(...) but the variables themselves are never changed.

Note that if your variables and parameters are object references the values that are copied are the references(think of them as the object's address) and not the objects themselves.

So let's change the example to use AtomicInteger which let's us change the value of the object:

AtomicInteger someMethod(AtomicInteger param) {
    try {
        param.incrementAndGet();
        return param;
    } finally {
        //decrement twice after "copying" the return value
        param.decrementAndGet();
        param.decrementAndGet();
    }
}

void test() {
  AtomicInteger a = new AtomicInteger(2);
  AtomicInteger b = someMethod(a);
}

Now param will be a copy of the reference a and b will be a copy of the reference param. In the end, all 3 references "point" to the same instance of AtomicInteger. Thus, the increment and decrement operations affect them all which means they all return the same value - 1.

So how do I fix my code?

To fix your code you'd need to get the values of flow1 and flow2, e.g. like this:

TwoFlows twoFa = new TwoFlows(f2, f3);
twoFa.adjustDistance();
System.out.println(formatF1F2F3(f1,twoFa.flow1,twoFa.flow2));
Thomas
  • 87,414
  • 12
  • 119
  • 157
0

Float variables are primitive Java types so when you pass them in a method or constructor, they are passed by value, not by reference. This means that whatever changes happen to the variables f1, f2, f3 inside your static class and method adjustDistance(), they are only 'visible' inside that class. When you try to print the values in your main method, you are just printing the original float values which have not been changed. If you want print the changed values, I propose the following:

System.out.println(formatF1F2F3(f1,f2,f3));
System.out.println(formatF1F2F3(f1,twoFa.flow1,twoFa.flow2));
System.out.println(formatF1F2F3(twoFb.flow1,twoFb.flow2,f3));     
System.out.println(formatF1F2F3(f1,twoFc.flow1,twoFc.flow2));