1

I have been playing around with Java and cannot quite understand how java methods work with objects which are passed to them.

For example, In the code below i create some "Container" object instances which contains another object and a primitive. When i pass this "Container" object to methods, I can change the object that is held inside the container instance either directly modfying its value or using the new operator to construct a new object and replace its original. These changes are permanent as their values are that of the new objects when examined outside the method.

What is confusing me greatly is that although i can change a Containers inner object via methods, I cannot actully change the container itself. By this i mean that if i pass a container to a method and try to alter it via swapping or assignment from the new operator.

Below is the code i use to test the modification of an object instances attributes and then modification of the actual instance itself.

class InsideRef{
    char myChar;
    InsideRef(char newVal){
        myChar = newVal;
    }
}

class Container{
    InsideRef myInRef = null;
    int myPrimitive = 0;
    Container(char innerChar, int innerPrim){
        myInRef = new InsideRef(innerChar);
        this.myPrimitive = innerPrim;
    }
    public void myDetails(){
        System.out.format("Container.%s => myPrimitive -> %d || myInRef => %s -> %c.%n",
        this.hashCode(),this.myPrimitive,this.myInRef.hashCode(),this.myInRef.myChar);
    }
}

class AttribRefModder{
    public static void ModObjRefVal(Container toEdit){
        toEdit.myInRef.myChar = 'Z';
    }
    public static void ModNewObjReference(Container toEdit){
        toEdit.myInRef = new InsideRef('Y');
    }
}

class RefSwapper{
    public static void RefSwap(Container A, Container B){
        System.out.println("Swapping....");
        System.out.print("OBJECT A -> ");
        A.myDetails();
        System.out.print("OBJECT B -> ");
        B.myDetails();
        Container temp = A;
        A = B;
        B = temp;
        System.out.print("SWAPPED A -> ");
        A.myDetails();
        System.out.print("SWAPPED B -> ");
        B.myDetails();
        System.out.println("Exiting....");
    }
    public static void RefNew(Container A){
        System.out.println("Assigning Reference New Object....");
        A = new Container('V',999);
        System.out.print("NEW C REF -> ");
        A.myDetails();
        System.out.println("Exiting....");
    }
}

public class ReferenceModding{
    public static void main(String[] args){
        System.out.println("-----------MODDING INNER REFS----------");
        Container C1 = new Container('A', 111);
        System.out.print("ORIGINAL A -> ");
        C1.myDetails();
        AttribRefModder.ModObjRefVal(C1);
        System.out.print("MODDED A.Ref -> ");
        C1.myDetails();
        AttribRefModder.ModNewObjReference(C1);
        System.out.print("NEW A.Ref -> ");
        C1.myDetails();
        System.out.println("----------SWAPPING REFERENCES----------");
        Container C2 = new Container('B',222);
        RefSwapper.RefSwap(C1, C2);
        System.out.print("OBJECT A -> ");
        C1.myDetails();
        System.out.print("OBJECT B -> ");
        C2.myDetails();
        System.out.println("----------ASSIGN NEW OBJECTS----------");
        Container C3 = new Container('C',333);
        System.out.print("OBJECT C -> ");
        C3.myDetails();
        RefSwapper.RefNew(C3);
        System.out.print("OBJECT C -> ");
        C3.myDetails();
    }
}

I apologise if this is too much code i have posted. It's just i've been playing with Java all day and this object parameter business has really confused me. I cant work out why Java methods allows me to edit and assign a new object to the InsideRef refrences that are held inside a container class but do not allow me to perform the same operations on the actual container classes.

Thanks for any help you may be able to provide.

Pike Man
  • 355
  • 2
  • 4
  • 13

4 Answers4

2

You have stated the characteristic of Java correctly.

Under the covers, you pass a reference -- a memory address is a good model -- of an object. So you can change anything referred to by that reference.

But you cannot change what the caller thinks of as "that object" -- the caller has a memory address containing the address passed to you, and you cannot change that. So regardless of what you do, you cannot change which object is referred to, only what is 'inside' that object.

arcy
  • 12,845
  • 12
  • 58
  • 103
  • To be exact, you pass a reference _by value_ (i.e. a copy of the reference), which is why the reference of the caller cannot be changed by the method. – GriffeyDog Jan 16 '14 at 21:01
2

I think the confusion comes from this part in RefSwap:

Container temp = A;
A = B;
B = temp;

In Java, this only affects the variables A and B within that method. It won't change what objects A and B point to when the method returns to the location where it was called from. So in main the objects C1 and C2 still refer to the same Container objects, these are not swapped around.

Simeon Visser
  • 118,920
  • 18
  • 185
  • 180
0

Parameter passing in java is always by value. This meaning that having a parameter in the left side of an assignment has no effect at all outside the method call; it just changes the value of the reference (pointer) you copied on the method call stack, so you have lost that value for the rest of the method.

For example, PL/SQL has a true parameter passing by reference, if you declare there

-- True pass-by-reference
procedure my_procedure(my_integer out integer) is
begin
  my_integer := 6;
end;

You will see after the procedure call that the integer you passed there has changed its value. However, java does not support this parameter passing. Think of something like this in C:

// Just stepping on the values on the method call stack
void my_function(int* my_integer) {
   my_integer = 0;
}

Does this change the value of the integer referenced by the pointer? No, it just crunches the pointer value. This is what you do with your

A = new Container('V',999);

I hope this has been of any help to you :)

Jorge_B
  • 9,712
  • 2
  • 17
  • 22
0

When i pass this "Container" object to methods

The first thing you need to understand is it's not possible to "pass" an "object". The only types in Java are primitive types and reference types. That means every value is either a primitive or a reference. A "reference" is a pointer to an object. The type Container is a reference type -- it is the type of a pointer to an object, specifically, a pointer to instances of the class Container.

newacct
  • 119,665
  • 29
  • 163
  • 224