Клонирование объектов без реализации клонируемого интерфейса
Чтобы клонировать объект, мне нужно реализовать "клонируемый" интерфейс. потому что здесь мой класс - это jar-файл (я имею в виду API). поэтому я не могу редактировать класс. Я слышал, что все классы расширяют базовый класс объектов, и этот класс объектов реализует клонируемый интерфейс. Означает ли это, что мы можем напрямую клонировать объект без реализации интерфейса? Если так, то в моем затмении у меня нет возможности клонировать объект. Есть ли другой способ клонирования объекта без реализации клонируемого интерфейса. пожалуйста, объясни.
7 ответов
Ява Object
класс не реализует Cloneable
интерфейс. Это, однако, имеет clone()
метод. Но этот метод protected
и бросит CloneNotSupportedException
если вызывается на объекте, который не реализует Cloneable
интерфейс. Поэтому, если вы не можете изменить класс, который хотите клонировать, вам не повезло, и вам нужно будет найти другой способ скопировать экземпляр.
Однако следует отметить, что система клонирования в Java полна дыр и, как правило, больше не используется. Проверьте это интервью с Джошем Блохом от 2002 года, объясняющим несколько вопросов.
Обычно лучше избегать clone(), потому что это трудно сделать правильно ( http://www.javapractices.com/topic/TopicAction.do?Id=71). Возможно, у рассматриваемого класса есть конструктор копирования?
В качестве альтернативы, если он реализует Serializable или Externalizable, вы можете глубоко скопировать его, записав его в поток байтов и прочитав его обратно в
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Object deepCopy = ois.readObject();
(с http://www.jguru.com/faq/view.jsp?EID=20435). Это быстро и легко, но не красиво... Я бы вообще посчитал это последним средством.
Это API, который клонирует объект без реализации клонируемого интерфейса.
Попробуй это
https://github.com/kostaskougios/cloning
Также вы можете найти более подробную информацию о клонировании объектов здесь
http://javatechniques.com/blog/faster-deep-copies-of-java-objects/
Необязательно реализовывать клонируемый интерфейс для создания клона объекта. Вы можете написать свой собственный метод клонирования в классе, объект которого вы хотите клонировать.
Вы можете использовать Unsafe для создания экземпляра объекта, а затем скопировать значения в новый экземпляр с помощью отражения Java. Но, как следует из названия Unsafe, это не совсем хорошее решение.
public static Unsafe unsafe;
static {
Field f;
try {
f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
unsafe = (Unsafe) f.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
public static <T> T clone(T object) throws InstantiationException {
T instance = (T) unsafe.allocateInstance(object.getClass());
copyInto(object,instance);
return instance;
}
public static void copyInto(Object source,Object destination){
Class<?> clazz = source.getClass();
while (!clazz.equals(Object.class)) {
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
try {
field.set(destination, field.get(source));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
clazz = clazz.getSuperclass();
}
}
Метод clone() в классе Object защищен, что означает, что все классы будут наследовать его с модификатором защищенного доступа, поэтому, если вы попытаетесь получить к нему доступ вне этого класса, не клонируя его, вы его не увидите, а также вы получите исключение CloneNotSupportedException, если вы попытаетесь вызвать его без реализации Cloneable интерфейса.
В случае, если вы ищете способ создать поведение клона, вам нужно написать новый метод в вашем классе, а затем создать копию всех полей в нем, это в основном похоже на создание новой копии существующего состояния объект.
public class TestCloneable {
private String name = null;
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the name
*/
public String getName() {
return name;
}
public TestCloneable createCopy(){
TestCloneable testCloneable = new TestCloneable();
testCloneable.setName(this.getName());
return testCloneable;
}
}
Попытка вызвать метод clone для класса, который не реализует Cloneable, выдает исключение CloneNotSupported, и никакой класс Object не реализует Cloneable.
вот Javadoc из метода клона класса Object
CloneNotSupportedException if the object's class does not
* support the <code>Cloneable</code> interface. Subclasses
* that override the <code>clone</code> method can also
* throw this exception to indicate that an instance cannot
* be cloned.
Кроме того, метод Object#clone защищен, поэтому вам необходимо реализовать метод clone в вашем классе и сделать его общедоступным, чтобы он мог быть доступен для классов, создающих объекты вашего класса, которые затем могут вызывать clone. Хорошим примером является способ реализации клона в ArrayList
ArrayList реализует клонируемый, как показано ниже открытый класс ArrayList расширяет AbstractList реализует List, RandomAccess, Cloneable, java.io.Serializable
а затем реализует метод клонирования:
/**
* Returns a shallow copy of this <tt>ArrayList</tt> instance. (The
* elements themselves are not copied.)
*
* @return a clone of this <tt>ArrayList</tt> instance
*/
public Object clone() {
try {
ArrayList<E> v = (ArrayList<E>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}