LinkedList Clone Implementation

I am trying to implement the clone() method on a DoubleLinkedList . Now the problem is that implementing this “agreement” is much more complicated than just creating a new DoubleLinkedList and populating it with all the elements of my current DoubleLinkedList.

Are there any inconveniences that I do not see at the same time?

Here is my current approach:

 @Override public DoubleLinkedList<T> clone() { DoubleLinkedList<T> dll = new DoubleLinkedList<T>(); for (T element : dll) { dll.add(element); } return dll; } 

Here is what would happen by convention:

 @Override public DoubleLinkedList<T> clone() { try { DoubleLinkedList<T> dll = (DoubleLinkedList<T>)super.clone(); //kinda complex code to copy elements return dll; } catch (CloneNotSupportedException e) { throw new InternalError(e.toString()); } } 
+4
source share
4 answers

As you rightly point out, the convention should always call super.clone() at the beginning of the implementation of clone() . From the docs API to Object#clone() :

By convention, the returned object must be received by calling super.clone. If a class and all its superclasses (except Object) obey this convention, this will be the case when x.clone (). GetClass () == x.getClass ().

Your first attempt (without using super.clone() ) has the following problem:

Let's pretend that

 class IntDoubleLinkedList extends DoubleLinkedList<Integer> implements Cloneable 

(and that IntDoubleLinkedList does not get the clone() override), and I run the following code:

 IntDoubleLinkedList idll = new IntDoubleLinkedList(); IntDoubleLinkedList idll2 = (IntDoubleLinkedList) idll.clone(); 

What will happen? The clone method of your DoubleLinkedList will be executed, which, if it does not go through super.clone (), returns an instance of DoubleLinkedList , which, in turn, cannot be sent to the IntDoubleLinkedList . A ClassCastException will be thrown!

So how super.clone() solve this problem? Well, if everyone adheres to the convention of calling super.clone() in the overriden clone method, Object.clone() will eventually be called, and this implementation will instantiate the appropriate type ( IntDoubleLinkedList in this case)!

+5
source

As others have explained, if you intend to override clone , you must obey its contract.

If you like the way you use it, just make DoubleLinkedList not Cloneable and turn your implementation into a copy constructor or static factory method. The static factory method has the added benefit of providing a type inference bit for generic type arguments.

PS LinkedList is a doubly linked list.

+1
source

If you do this by creating a new list and adding all the elements from the source, if you then do something like:

 DoubleLinkedList<Foo> l1 = new DoubleLinkedList<Foo>(); l1.add (new Foo(params)); DoubleLinkedList<Foo> l2 = l1.clone(); Foo foo = l2.get(0); foo.setProperty("new Value"); 

foo.property will be the "new value" in both lists (also, on the contrary, if you change it to l1, the changes will appear in l2). The correct way would be to actually clone each item and add a clone to ensure list independence. Please note that this only happens if you change the properties of the elements and not add, move or remove them from the list.

Edit: just realized that since this is a linked list, the next / previous elements are properties of the element, so even adding, deleting, affects both lists.

0
source

The reason why the “convention” is to call super.clone() is to ensure that the final type of the cloned object matches the object that is being cloned. For example, if you create your own new DoubleLinkedList in the clone() method, which is good now, but later, if the subclass cannot override clone() , it will return a clone that is a DoubleLinkedList and not its own class. (He will also not be able to clone additional fields if there are any, perhaps so big problems arise.)

In this sense, the traditional method is preferred, and it is really awkward.

However, both implementations have a similar problem: you are not deep copying data structures. A clone is a shallow cop. This is probably not what the subscriber expects. You will need to go through and replace each value in the DoubleLinkedList with the cloning of the value, as well as for other non-primitive fields.

In this sense, the usual method will give the wrong result here! You need a third way. Your first method probably just works, except that you need to add element.clone() , for example.

0
source

Source: https://habr.com/ru/post/1311725/


All Articles