Вопрос

Consider the following from Effective Java Item 11 (Override clone judiciously) where Josh Bloch is explaining what is wrong with the clone() contract .

There are a number of problems with this contract. The provision that “no constructors are called” is too strong. A well-behaved clone method can call constructors to create objects internal to the clone under construction. If the class is final, clone can even return an object created by a constructor.

Can someone explain what Josh Bloch is saying in the first paragraph by "If the class is final, clone can even return an object created by a constructor." What does final have to do with clone() here?

Это было полезно?

Решение

If a class is not final, clone has to return the most derived class for which it was called. That can't work with a constructor, because clone doesn't know which one to call. If a class is final, it can't have any subclasses, so there's no danger in calling its constructor when cloning.

Другие советы

It's because typical implementations of clone() look like this:

public class MyClass implements Cloneable {
  protected Object clone() {
    MyClass cloned = (MyClass) super.clone();
    // set additional clone properties here
  }
}

In this way you can inherit the cloning behavior from your superclass. It's widely assumed that the result of a clone() operation will return the correct instance type based on the object it was called on. Ie. this.getClass()

So if a class is final, you don't have to worry about a subclass calling super.clone() and not getting the right object type back.

public class A implements Cloneable {
    public Object clone() {
       return new A();
    }
}


public class B extends A {
    public Object clone() {
       B b = (B)super.clone(); // <== will throw ClassCastException
    }
}

But, if A is final, no one can extend it, and thus it's safe to use a constructor.

A class doesn't have to provide its own implementation of clone in order to be cloneable. It can delegate that to its cloneable superclass. Here comes the catch: clone must always return an instance of the same class as the instance it is called on. That is impossible to achieve in the described case if an explicit constructor is called. If the class overridng clone is final, on the other hand, this would be fine.

The contract for clone specifies that "By convention, the returned object should be obtained by calling super.clone". If your class is not final and you return something obtained with a constructor invocation, calling super.clone() from a subclass will not return the expected result (first of all, the type of the returned object will not be the type of the subclass, as the native clone() method would return).

See Jorado answer. This is the explanation. In additional clone has problem in final fields see : http://en.wikipedia.org/wiki/Clone_%28Java_method%29#clone.28.29_and_final_fields

You also should read Josh interview on clone in: http://www.artima.com/intv/bloch13.html

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top