18

In this question and this post is explained how to clone objects with final fields by using protected copy constructors.

However, supposing that we have:

public abstract class Person implements Cloneable
{
    private final Brain brain; // brain is final since I do not want 
                // any transplant on it once created!
    private int age;
    public Person(Brain aBrain, int theAge)
    {
        brain = aBrain; 
        age = theAge;
    }
    protected Person(Person another)
    {
        Brain refBrain = null;
        try
        {
            refBrain = (Brain) another.brain.clone();
            // You can set the brain in the constructor
        }
        catch(CloneNotSupportedException e) {}
        brain = refBrain;
        age = another.age;
    }
    public String toString()
    {
        return "This is person with " + brain;
        // Not meant to sound rude as it reads!
    }
    public Object clone()
    {
        return new Person(this);
    }

    public abstract void Think(); //!!!!
    …
}

Returns an error since we can't instantiate an abstract class. How can we solve this?

justHelloWorld
  • 6,478
  • 8
  • 58
  • 138
  • 2
    When you bother to override `clone`, don't forget that you may make the return type more specific (`Person` instead of `Object`) and that it doesn't need to declare `throws CloneNotSupportedException` (you should probably do this for `Brain`). – maaartinus Jun 14 '17 at 11:12
  • 2
    I can't help but stop and think that your question effectively amounts to "How do I clone a Person?" and none of us think that's odd because we're programmers. – Pharap Jun 14 '17 at 16:11
  • I think it is more a design problem. If all the possible implementation of Person class are unkwown, I would ask myself if using inheritance in this case is right. Can the problem be solved using composition? Which is a possible implementation of Person? Because if you can use composition, the solution is easy, it is just a call to the constructor of Person and set all the variable, otherwise, if inheritance is important, you know that you need a `Person clone()` method in Person, so declare it abstract and all the implementation will decide how to implement it. Hope it helps, cheers! – rascio Jun 17 '17 at 13:04

4 Answers4

21

You don't implement the clone() method in the abstract class, only in the concrete sub-classes.

public class SomeConcretePerson extends Person
{
    public SomeConcretePerson (SomeConcretePerson another)
    {
        super (another); // this will invoke Person's copy constructor
    }

    public Object clone()
    {
        return new SomeConcretePerson(this);
    }
}
Eran
  • 387,369
  • 54
  • 702
  • 768
7

In some rare cases, we might not be able to use the copy constructor technique and have to use the clone() method. For these cases, it’s worth knowing that Java offers a work-around for the final field problem:

public abstract class Person implements Cloneable {
    private final Brain brain;
    private int age;
    public Person(Brain aBrain, int theAge) {
        brain = aBrain; 
        age = theAge;
    }
    @Override public String toString() {
        return "This is person with " + brain;
        // Not meant to sound rude as it reads!
    }
    @Override public Person clone() {
        try {
            Person clone = (Person)super.clone();
            Field brainField=Person.class.getDeclaredField("brain");
            brainField.setAccessible(true);
            brainField.set(clone, brain.clone());
            return clone;
        } catch (CloneNotSupportedException|ReflectiveOperationException ex) {
            throw new AssertionError(ex);
        }
    }

    public abstract void think();

    …
}

The possibility to override the final restriction was created for exactly such use cases, cloning or deserializing an object, where no constructor will be called. The Java Language Specification, §17.5.3. Subsequent Modification of final Fields states:

In some cases, such as deserialization, the system will need to change the final fields of an object after construction. final fields can be changed via reflection and other implementation-dependent means. The only pattern in which this has reasonable semantics is one in which an object is constructed and then the final fields of the object are updated. The object should not be made visible to other threads, nor should the final fields be read, until all updates to the final fields of the object are complete.

This is exactly how the example works, setting the final field right after the clone’s construction, before the clone is exposed to anyone, and not reading any field.

As said, cases in which this is required, are rare. As long as you can implement a copy constructor based solution, use that.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • You forgot to mention that this solution (and any reflection based on reflection ftm) *breaks silently* whenever the affected fields are renamed, and this will become a problem not earlier than runtime. – hiergiltdiestfu Jun 14 '17 at 15:01
  • @hiergiltdiestfu: indeed, though the field and the `clone` method reside in the same class and audit tools should be able to check the correctness via static code analysis. But generally, using Reflection implies loosing compile-time checks… – Holger Jun 14 '17 at 15:21
0

If you just want a new instance of the class without cloning the values of its members then you can use the following:

public  static < T > T getNewInstance ( Class <T> type )
{
    try 
    {
        return type.newInstance()  ;
    } catch ( InstantiationException | IllegalAccessException e) 
    {
        e.printStackTrace();
    }
    return null ;
}

For deep cloning of objects you can use com.rits.cloning.Cloner utility. For eg. :

private T clone(T resource){

    Cloner cloner = new Cloner();
    T cloneObject = (T) cloner.deepClone(obj);
    return cloneObject;
}
Varshney P.
  • 208
  • 1
  • 12
0

We can't instantiate an abstract class but we can do it in the subClass

class Teacher extends Person {

    public Teacher(Brain aBrain, int theAge) {
        super(aBrain, theAge);
    }

    protected Teacher(Person another) {
        super(another);
    }


    public Object clone() {
        return new Teacher(this);
    }
}
lihongxu
  • 754
  • 5
  • 14