Объект клонирован, но статические ссылки все еще существуют?

Я узнал об объектном глубоком клонировании, у меня есть класс сотрудников с методом getInstance, который возвращает одноэлемент, и я клонирую возвращаемый объект. Ниже приведен класс и класс теста.

public class Employee  implements Serializable , Cloneable {

    public static Employee employee;

    private String name;

    private int age;


    private Employee(){


    }


    public Employee(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    protected Object clone() throws CloneNotSupportedException {

        return super.clone();

        }


    public static Employee getInstance(){

        if(employee == null ){
            employee = new Employee();
            return employee;
        }


        return employee;
    }


    public String getName() {
        return name;
    }


    public void setName(String name) {
        this.name = name;
    }


    public int getAge() {
        return age;
    }


    public void setAge(int age) {
        this.age = age;
    }



}

Класс тестовой копии объекта

public class CopyTest {

    /**
     * @param args
     */
    public static void main(String[] args) {



        try {

            Employee original = Employee.getInstance();

            original.setName("John");
            original.setAge(25);

            Employee cloned = (Employee)copy(original);

            System.out.println("Original -->"+Employee.getInstance().getName());

            cloned.getInstance().setName("Mark");

            System.out.println("Cloned -->"+cloned.getInstance().getName());

            System.out.println("Original -->"+Employee.getInstance().getName());

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }


    public static Object copy(Object orig) {
        Object obj = null;
        try {
            // Write the object out to a byte array
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(bos);
            out.writeObject(orig);
            out.flush();
            out.close();

            // Make an input stream from the byte array and read
            // a copy of the object back in.
            ObjectInputStream in = new ObjectInputStream(
                new ByteArrayInputStream(bos.toByteArray()));
            obj = in.readObject();
        }
        catch(IOException e) {
            e.printStackTrace();
        }
        catch(ClassNotFoundException cnfe) {
            cnfe.printStackTrace();
        }
        return obj;
    }
}

Вывод

Original -->John
Cloned -->Mark
Original -->Mark

проблема

Несмотря на то, что я клонировал исходный объект, чтобы создать его копию,

Employee cloned = (Employee)copy(original);

И я изменяю свойство клонированного объекта, вызывая

cloned.getInstance().setName("Mark");

Он отражает исходный объект, как вы можете видеть из вывода консоли. Я предполагаю, что это из-за статического вызова? , и как мне это преодолеть? Я нарушаю принцип, что мне нужен один экземпляр объекта методом getInstance, а затем я решил позже сделать копию объекта.

0
источник поделиться
4 ответа

Это то, что говорится в учебной странице JAVA Doc:

Поля, которые имеют статический модификатор в своем объявлении, называются статическими полями или переменными класса. Они связаны с классом, а не с каким-либо объектом. Каждый экземпляр класса использует переменную класса, которая находится в одном фиксированном месте в памяти. Любой объект может изменить значение переменной класса, но переменные класса также можно манипулировать, не создавая экземпляр класса.

Клонировать объект cloned только другой объект класса. Он не меняет другой объект, к которому у него нет ссылки. Ваш звонок cloned.getInstance() возвращает статический объект employee, к которому все объект может получить доступ, потому что статический объект ассоциированный с Class, а не какой - либо конкретный объект. Поэтому вы вызываете cloned.getInstance().setName("Mark"); просто эквивалентно Employee.employee.setName("Mark");

0
источник

Вы устанавливаете имя Employee экземпляра static поля employee

cloned.getInstance().setName("Mark");
      ^ static method call that returns the employee reference

и распечатать его тоже

System.out.println("Cloned -->"+cloned.getInstance().getName());
                                      ^ static method call

Возможно, вы захотите изменить cloned экземпляр

cloned.setName("Mark");
System.out.println("Cloned -->"+cloned.getName());
+1
источник

Статическое поле примерно означает, что он будет использоваться каждым объектом. Независимо от того, сколько объектов вы создали/клонировали, ваш getInstance() вызовет тот же Employee.

Поэтому, как только вы укажете свое имя Mark, вы всегда получите Mark на консоли.

Например:

Employee me = new Employee();
Employee.getInstance().setName("Mark");
System.out.println("me employee name? " + me.getInstance().getName());

Не удивляйтесь, если вы получите "Mark" в консоли;)

Для получения более подробной информации о различиях между членами экземпляра и класса (с использованием статического ключевого слова) см. Этот раздел учебника

+1
источник

Вы захотите сериализовать объект, а затем десериализовать его. В java, десериализации гарантируется создание нового объекта. (имеет отношение к тому, как работает Classloader).

Когда вы сериализуете объект, он выполняет глубокую копию объекта и всех его зависимостей и т.д. Сериализация может использоваться несколькими способами, но один из способов - преобразовать объекты в байты, чтобы их можно было отправить по проводу ( сеть) или сохранены на диске для сохранения. Вы можете использовать поведение для сериализации/десериализации в памяти и создавать новый объект каждый раз с точно таким же содержимым (значениями), но с другой ссылкой, чем оригинал.

здесь метод, который я работаю в производстве в некоторых приложениях:

/**
 * Clones an object creating a brand new
 * object by value of input object. Accomplishes this
 * by serializing the object, then deservializing it.
 * 
 * @param obj Input Object to clone
 * @return a new List<Product> type cloned from original.
 * @throws IOException If IOException
 * @throws ClassNotFoundException If ClassNotFoundException
 */
private static List<Product> cloneProdList(Object obj) throws IOException, ClassNotFoundException {

    java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream();
    java.io.ObjectOutputStream obj_out = new java.io.ObjectOutputStream(bos);
    obj_out.writeObject(obj);

    java.io.ByteArrayInputStream bis = new java.io.ByteArrayInputStream(bos.toByteArray());
    java.io.ObjectInputStream obj_in = new java.io.ObjectInputStream(bis);

    @SuppressWarnings("unchecked")
    List<Product> newObj = (List<Product>)obj_in.readObject();

    bos.close();
    bis.close();
    obj_out.close();
    obj_in.close();

    return newObj;
}
0
источник

Посмотрите другие вопросы по меткам или Задайте вопрос