0

Josh Bloch wrote in the Effective Java:

Many consider clone and Cloneable broken in Java, largely because the rules for overriding clone are tricky and difficult to get right

and he recommends use clone constructor.

Sonar has rule "clone" should not be overridden forbidding use clone method. And Sonar recommends use clone constructor too.

I tried to use clone constructor and I got a some problem.

I have class with generics:

public class ClassA<T extends InterfaceB>
{
   private T fieldB;
}

I have 3 implementation of InterfaceB: ClassB1, ClassB2, ClassB3. And I would like implement deep clone constructor for the ClassA.

I tried to do so:

//...
public ClassA(ClassA object)
{
    if (object.fieldB instanceof ClassB1 objectB1)
    {
        this.fieldB = new ClassB1(objectB1);
    }
    if (object.fieldB instanceof ClassB2 objectB2)
    {
        this.fieldB = new ClassB2(objectB2);
    }
    if (object.fieldB instanceof ClassB3 objectB3)
    {
        this.fieldB = new ClassB3(objectB3);
    }
}
//...

I think this code is awful:

  • If somebody add new implementation ClassB4 he should add new if block in this constructor. I think with 100% chance they will forget to do. This will result in a clone error.
  • This code is hard to read

When I using the classic method "clone" I don't have this problem. I call object.field.clone() and it works.

I have a question: What is the best way to deep clone by constructor if case uses generic fields

Gleb Shadrin
  • 83
  • 1
  • 1
  • 5
  • Unless I'm missing something I don't think the complexity has anything to do with the class being generic; rather, it's due to the fact that `fieldB` can be one of multiple subclasses, and you want to clone it as well as the outer object (a deep clone). You'd have the same issue if it were non-generic, and `fieldB` were of type `InterfaceB`. – M. Justin Aug 09 '23 at 15:36
  • I'd look at https://stackoverflow.com/questions/64036/how-do-you-make-a-deep-copy-of-an-object for ideas. – M. Justin Aug 09 '23 at 15:37
  • @M.Justin yes, generics is a special case for example – Gleb Shadrin Aug 09 '23 at 15:41

1 Answers1

0

For this specific case you could add a copy method to InterfaceB and call that. By being a method on the interface, it forces all implementations to implement it, so it can't be missed.

public interface InterfaceB<T extends InterfaceB<T>> {
    T copy();
}
public class ClassB1 implements InterfaceB<ClassB1> {
    @Override
    public ClassB1 copy() {
        return new ClassB1(); // TODO: Create a copy here
    }
}
public class ClassA<T extends InterfaceB<T>>
{
   private T fieldB;

   public ClassA(ClassA<T> object) {
      this.fieldB = object.fieldB.copy();
   }
}
M. Justin
  • 14,487
  • 7
  • 91
  • 130