I'm working on a system for saving and recalling screen states, this is my first time messing with this kind of stuff so I'm not really sure what the best way to go about this is but I currently store all the "PreviewMonitor" objects (about 40 or so) inside of an array list. The problem is that when I create a copy of the ArrayList titled "allPreviewMonitors" to be stored I end up with an ArrayList with elements that are constantly changing as they original elements are updated. It's almost as if I'm working with the original ArrayList when in fact, it should be an entirely different ArrayList with a 'frozen' version of the elements and their states when I created the copy of allPreviewMonitors. Why is this behavior happening? If need be I can show code, but I'm not sure it's needed here.
问题:
回答1:
You are only copying object references into your ArrayList. You need to copy the objects themselves.
In Java, all object variables are actually reference variables. So the code:
Myclass myObject = new Myclass();
Myclass otherObject = myObject;
creates a Myclass object and stores a reference to that Myclass object in the reference variable myObject
. It then creates a new reference variable otherObject
and the reference data (eg a memory address) is copied from myObject
to otherObject
. These now refer to the same object in memory. At this point, the line
myObject.myMethod();
has the same results as
otherObject.myMethod();
What you are getting in your ArrayList are different references to the same objects. What you want is one of the following:
Myclass otherObject = myObject.clone(); // use the clone function
// OR
Myclass otherObject = new Myclass(myObject); // use a copy constructor
If you put your objects into the ArrayList using clone()
or a copy constructor, your ArrayList will contain references to identical copies, rather than references to the same copies.
As others have pointed out, just making copies of the references is called a 'shallow copy', while making copies of the objects that are referred to is called a 'deep copy'.
Edit: In order for this to work, your solution has to be implemented not just on your class, but on all the classes that you include in side your class. For example, consider MyClass
which has a field of type OtherClass
:
class MyClass {
private String foo;
private OtherClass bar;
private int x;
MyClass(String f, OtherClass b, int x) {
foo = f;
bar = b;
this.x = x;
}
MyClass(MyClass o) {
//make sure to call the copy constructor of OtherClass
this(new String(o.foo), new OtherClass(o.bar), o.x);
}
// getters and setters
}
Note that this requires OtherClass
to also have a copy constructor! And if OtherClass
references other classes then they too need copy constructors. There's no way around that.
Finally, your list copy would look like:
List<MyClass> myNewList = new ArrayList<>(myExistingList.size());
for ( MyClass item : myExistingList) {
// use the copy constructor of MyClass, which uses the copy constructor of OtherClass, etc, etc.
myNewList.add(new MyClass(item))
}
回答2:
An Arraylist
like all Collections
, contains only references to objects.
it is not enough to copy the List, you also must clone() the elements (or create new ones, or use a copy constructor) in the list while creating the copy of the List.
This is called making a "Deep Copy", while you currently have a "Shallow Copy".
回答3:
You need to ensure you do a "deep copy" — that is, clone the PreviewMonitor
object. By default, you'll just be doing a shallow copy and duplicating the reference to the same object.
回答4:
To clone, you can't just return the current object. You have to create a new object with the same values as the current object. In other words, use the constructor of the current object's Class and create a new object. Make sure the attributes match up between the old object and the new object. Return the new object and repeat for every object in the original list.