2

I don't fully understand when Java passes a copy/value and when it passes a "reference" (the pointer).

I'm trying to assign a copy of a static object I have, but I'm not sure how to go about it.

I have this:

static ArrayList<MyObject> myObjects;

I want to get a copy of myObjects so that I can play around with the values without affecting the original. Does it pass a reference or a copy/value when I use a getter like so:

public static ArrayList<MyObject> getMyObject()
{
    return ThisClass.myObjects;
}

What does that return? If it's a reference, how can I get a copy?

I've seen these:

(How do I copy an object in Java?)

(Java: getter method vs. public instance variable: performance and memory)

(Is Java "pass-by-reference" or "pass-by-value"?)

(How can Java assignment be made to point to an object instead of making a copy?)

But I still don't quite understand what I'll get back.

Community
  • 1
  • 1
RileyE
  • 10,874
  • 13
  • 63
  • 106

4 Answers4

5

Java will always return a reference and not a copy as long as it's not a primitive type (aka long,int,short,etc or one of the primitive wrappers Long,Integer, Short.

To get a copy you will need to either copy the data, use a copy constructor, or use the method clone which will create a new object with the appropriate values.

Example of a copy constructor with a list, by default this is a "shallow copy" meaning the objects inside are the same.

List<MyObject> myNewCopiedList = new ArrayList<MyObject>(oldList);

For a "deep copy", meaning the objects inside can be mutated without affecting the originals you will need to make a new List then add copies/clones of the object and add.

Example, assuming MyObject has a copy constructor or a clone method.

List<MyObject> myNewCopiedList = new ArrayList<MyObject>();
for (MyObject myo : oldList){
    myNewCopiedList.add(new MyObject(myo)); // if there is a copy constructor
    myNewCopiedList.add(myo.clone()); // if there is clone method
}
greedybuddha
  • 7,488
  • 3
  • 36
  • 50
  • This is excellent. I forgot ALL about deep copies and nearly had an issue with this. Thank you for all of the information! It's always a hassle to switch between languages, but this is a lot more like C than I was letting on. Again, this is amazing, so thank you! – RileyE Jun 04 '13 at 17:50
2

Think of it this way. Java is always pass by value.

For primitives, it is pass by value(actual value). For objects, it is pass by value-of-reference.

public int square(int a) { //The parameter a is copy of actual int itself.
//So now there are 2 ints
a=a*a;   //Only local copy a is actually modified. 
         //The integer variable passed(in caller function) is not modified.
return a;
}

If you call doSomething(d) where d is an object, a copy of reference pointing to this object is assigned to parameter a but there is only one object.

public void doSomething(Object a) { 
// Here the parameter is a reference which points to an 
//  object, not the object itself 
a.doMore(); //But doMore() does things using a different ref but on the same object.
            //The object can be modified!

Object b = new Object();  
a = b;   //Object referenced by passed parameter does not change but 
         //copy of reference now points to different object.
         // Now there is no reference of original object passed in this method.
}
user818510
  • 3,414
  • 26
  • 17
  • Okay. So, there really are pointers in Java that are being passed around, but they're seemingly "invisible"/unmarked. It's making more sense to me, now. Going through all of these answers has helped to get me thinking about the reallocation of memory, rather than thinking about "copying". – RileyE Jun 04 '13 at 17:52
1

Technically, Java is always pass-by-value. However, for a beginner's thinking, it's easier to think about it this way:

If it's a primitive type, it's pass-by-value.

If it's an object, it's pass-by-reference.

So in your example, you are returning a reference to the same static object in ThisClass. The reason I say this is technically pass-by-value is because your variable myObjects actually stores the memory address of the ArrayList<MyObject> which you declared, and it's this which is passed.

asteri
  • 11,402
  • 13
  • 60
  • 84
  • I think it's much better to think of class-type variables as holding "object identifiers". All parameters are passed by value; calling `PaintBooth.Spray(myCar)` when `myCar` holds `Car@14912C` would be analogous to someone at a repair shop writing the Vehicle Identification Number held in `myCar` on the top of a work order and submitting it to the paint booth, which then finds the car and paints it. The paint booth is not given a car; rather, it is given a *copy* of the VIN, and it uses that copy of the VIN to retrieve the car. – supercat Jun 04 '13 at 16:42
  • @supercat I like your analogy, but I don't see how it's much different from what I said. :) Whether you call it a "memory address" or an "object identifier", the concept is the same. – asteri Jun 04 '13 at 16:45
  • When a variable is passed by reference, the method receiving the variable is forbidden from persisting any reference to it. Anything that it is every going to do to that variable must be done before it returns. By contrast, when an object identifier is passed, the recipient is free to copy that identifier in any way it sees fit, and cause it to be used for any arbitrary purpose at any arbitrary time, even after the method has returned to its caller. – supercat Jun 04 '13 at 17:02
1

In order to properly make a copy of an object, one must know which non-primitive fields encapsulate

  • Mutable aspects of the object's state, but not its identity

  • The identity of an object and other immutable aspects, but no mutable aspects.

  • Aspects of the object which are expected never to be exposed to any code which might mutate them (and not identity)

  • Mutable aspects of the object's state, as well as its identity

Based upon what a field encapsulates, a correct copy of Foo

  • If one of Foo's field which encapsulates mutable state, a the corresponding field in a copy of Foo should hold a reference to a different object with the same state.

  • If a field encapsulates object identity, that field in the copy must hold a reference to the same object as in Foo--not a copy.

  • If a field encapsulates only immutable aspects other than identity, then a copy of Foo may either hold a reference to the same object as in Foo, or any object which has the same immutable state, as convenient.

  • If a field encapsulates both mutable state and identity, because the first two requirements will conflict, it will not be possible to copy the object in isolation.

In some cases, it may be possible to copy a set of mutable objects which use references to each other to encapsulate both state and identity. Such a copy must be performed on the set as a whole; for each object within the set, any field which in the original object encapsulates both the mutable state and identity of another object in the original set must in the copy refer to the corresponding object in the copied set.

supercat
  • 77,689
  • 9
  • 166
  • 211