0

I'm reading Effective Java by Joshua Bloch. I must say its a dense and complex book. The chapter on Methods Common to all objects (chapter 3) is proving hard for me to grasp as I've been programming for less than 3 years (1 year in java). I don't quite understand the concept of overriding the clone method appropriately. Can I get a simple to follow example of implementing clone, the right way as well as the wrong way? And why failing to invoke super.clone would cause a problem? what will happen?

Thank you in advance.

Horse Voice
  • 8,138
  • 15
  • 69
  • 120
  • 1
    Java's `clone` is basically broken. Josh Bloch himself said the following: *"If you've read the item about cloning in my book, especially if you read between the lines, you will know that I think clone is deeply broken. [...] It's a shame that Cloneable is broken, but it happens"* (see [this](http://stackoverflow.com/questions/2326758/how-to-properly-override-clone-method)). – arshajii May 14 '14 at 02:07
  • It's not clear what you are proposing when you say "without invoking super.clone". Where would you get the new object from? – newacct May 14 '14 at 23:20

2 Answers2

1

I'm reading that book myself. Not sure if I did everything "right" in this example, but maybe it'll help you understand.

Computer.java

package testclone;

public class Computer implements Cloneable {
    String OperatingSystem;

    protected Computer Clone() throws CloneNotSupportedException {
        Computer newClone = (Computer) super.clone();
        newClone.OperatingSystem = this.OperatingSystem;
        return newClone;
    }

}

MultiCore.java

package testclone;

public class MultiCore extends Computer implements Cloneable {
    int NumberOfCores;

    @Override
    protected MultiCore Clone() throws CloneNotSupportedException {
     //*********  use 1 of the next 2 lines  ***********           
        //MultiCore newClone = (MultiCore) super.clone();
        MultiCore newClone = new MultiCore();
        newClone.NumberOfCores = this.NumberOfCores;
        return newClone;
    }
}

TestClone.java

package testclone;

public class TestClone implements Cloneable {

    public static void main(String[] args) throws CloneNotSupportedException {
        //Computer myComputer = new Computer();
        //myComputer.OperatingSystem = "Windows";

        MultiCore myMultiCore = new MultiCore();
        myMultiCore.OperatingSystem = "Windows";    //field is in parent class
        myMultiCore.NumberOfCores = 4;

        MultiCore newMultiCore = myMultiCore.Clone();

        System.out.println("orig Operating System  = " + myMultiCore.OperatingSystem);
        System.out.println("orig Number of Cores   = " + myMultiCore.NumberOfCores);
        System.out.println("clone Operating System = " + newMultiCore.OperatingSystem);
        System.out.println("clone Number of Cores  = " + newMultiCore.NumberOfCores);

    }

}

Output:

orig Operating System = Windows

orig Number of Cores = 4

clone Operating System = null * This line is not what you want.

clone Number of Cores = 4

If you use the super.clone() line instead, then the Output is

orig Operating System = Windows

orig Number of Cores = 4

clone Operating System = Windows * Now it's what you want

clone Number of Cores = 4

So if you don't use super.clone(), it doesn't clone the fields in the parent (or grandparent, or great-grandparent, etc)

Good luck! (Sorry - the above looked formatted correctly when I typed it in, but for some reason looks awful when it actually shows)

Roy
  • 974
  • 6
  • 11
0

You should always use super.clone(). If you don't, and say just return new MyObject(this.x);, then that works fine for instances of MyObject. But if someone extends MyObject, it's no longer possible for them to get an instance of the right class when overriding your clone method. The one thing Object.clone does that you can't do a good job of yourself is creating an instance of the right class; the rest is just copying instance fields, which is drudgework you could have done yourself if you wanted.

amalloy
  • 89,153
  • 8
  • 140
  • 205
  • thank you. So whats the rule of thumb here? If I override the objects clone method in my personal class, then in my implementation of the clone method I better add to the top of that method, `super.clone()`? And if I choose to extend that class a few hierarchies down, I better make sure in each of my classes, I override object's clone method and in each override at the top add just `super.clone()`? And everything will be fine and dandy?? – Horse Voice May 14 '14 at 02:24
  • @TazMan: You don't just randomly write `super.clone();` at the top of a method. Rather, you use that to get the new object. If you don't use that, where would you get the new object from? amalloy's answer addresses the problem if you use `new CurrentClass()` to do it. What other alternative is there? Regarding overriding in subclasses, methods are inherited, so a subclass doesn't need to override the method unless it needs to do something additional to what the superclass's version does. – newacct May 14 '14 at 23:28