如何使用Java中的最终字段克隆抽象对象?

时间:2017-06-14 08:39:13

标签: java abstract-class clone

this问题中,本post解释了如何使用受保护的副本构造函数克隆具有最终字段的对象。

但是,假设我们有:

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(); //!!!!
    …
}

返回错误,因为我们无法实例化抽象类。我们怎样解决这个问题?

4 个答案:

答案 0 :(得分:19)

您不能在抽象类中实现clone()方法,只能在具体的子类中实现。

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);
    }
}

答案 1 :(得分:6)

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.

答案 2 :(得分:0)

如果您只想要一个新的类实例而不克隆其成员的值,那么您可以使用以下内容:

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

要深度克隆对象,可以使用 com.rits.cloning.Cloner 实用程序。例如。 :

private T clone(T resource){

    Cloner cloner = new Cloner();
    T cloneObject = (T) cloner.deepClone(obj);
    return cloneObject;
}

答案 3 :(得分:0)

我们无法实例化一个抽象类,但我们可以在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);
    }
}