Home > Back-end >  Using copy-in / copy-out passing in Java
Using copy-in / copy-out passing in Java

Time:01-31

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

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

CodePudding user response:

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));

CodePudding user response:

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));
  • Related