Как правильно реализовать вызов clone () в универсальном классе [Java] - PullRequest
0 голосов
/ 11 ноября 2018

У меня есть общий интерфейс, и я должен создать класс для его реализации. Сначала я подумал, что это будет работать нормально, указав в документации, что для интерфейса требуется класс, реализующий метод клона

genericClass<E extends Cloneable> implements genericInterface<E extends Cloneable>{
E data;

//code

public E get(){
return this.data.clone()
}
}

Однако на практике это не работает

package securedatacontainer;

public class Demo {


    public static void main(String[] args) throws CloneNotSupportedException {

        String s = "user";
        A a = new A(5, s);
        A b = a.clone();
        System.out.println("a equals b: " +(a.equals(b)));
        System.out.println("a == b: " + (a == b));


        B<A> c = new B<>(a);
        System.out.println("a equals c.data: " +(a.equals(c.data)));
        System.out.println("a == c.data: " + (a == c.data));

        A k = c.get();
        System.out.println(k.value);

    }

}


class A implements Cloneable{
    int value;
    String name;


    public A(int x, String str ){
        this.value = x;
        this.name  = str;
    }

    @Override
    public A clone() throws CloneNotSupportedException {
    A temp = new A(this.value, this.name);
    return temp;
    }


    public boolean equals(A elem){
        return (this.name).equals(elem.name) && this.value==elem.value;
    }
}




class B <E extends Cloneable>{
    E data;

    public B(E elem){
        this.data=elem;
    }

    public E get() throws CloneNotSupportedException{
        return (E) this.data.clone();
    }


}

Я получаю

Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - Erroneous sym type: java.lang.Cloneable.clone
    at securedatacontainer.B.get(Demo.java:60)
    at securedatacontainer.Demo.main(Demo.java:19)

Поскольку проект должен быть хранилищем данных, я действительно сомневаюсь, что мой учитель хочет какую-то поверхностную копию универсального элемента E (обратите внимание, что это простая тестовая программа для клона, а не сам проект). Может кто-нибудь сказать мне, почему это не работает или как я могу заставить его работать? Я не могу делать какие-либо предположения о входном элементе E, только что он имеет свой собственный метод clone ()

1 Ответ

0 голосов
/ 11 ноября 2018

Поскольку метод clone помечен как protected в классе Object, вы вообще не можете вызывать этот метод для произвольных объектов.Идея метода clone() заключается в том, что классы, которые его поддерживают, переопределяют метод, объявляя его открытым.

Единственное реальное решение, сохраняющее полную функциональность, - это использование отражения для доступа к методу и его обхода.модификаторы доступа.

Итак, вот мое решение,

public class B<E extends Cloneable> {
    E data;

    public B(E elem) {
        this.data = elem;
    }

    @SuppressWarnings("unchecked")
    public E get() {
        Method clone = null;
        try {
            clone = data.getClass().getMethod("clone");
            Object[] args = new Object[0];
            return (E) clone.invoke(data, args);
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException e) {
            throw new RuntimeException(e);
        }

    }
}

Clonable определяет поведение реализации защищенного клона объекта: если класс реализует Cloneable, метод клона объекта возвращает поле-полевой копии объекта;в противном случае выдает CloneNotSupportedException.Но способ, которым вы реализовали метод клонирования в классе A, не вызывает метод Object's clone, так что это не имеет никакого эффекта.

@Override
public A clone() throws CloneNotSupportedException {
    A temp = new A(this.value, this.name);
    return temp;
} 

Если вы хотите использовать это средство, у вас естьчтобы реализовать это так,

public class A implements Cloneable {
    int value;
    String name;

    public A(int x, String str) {
        this.value = x;
        this.name = str;
    }

    @Override
    public A clone() throws CloneNotSupportedException {
        return (A) super.clone();
    }

    public boolean equals(A elem) {
        return (this.name).equals(elem.name) && this.value == elem.value;
    }
}

В этом случае, если ваш класс A не реализует Cloneable, тогда java.lang.CloneNotSupportedException будет выброшено.

Наконец, объявление public class B<E extends Cloneable> дает вам ошибку компилятора, если вы попытаетесь передать что-то, что не реализует Cloneable, конструктору B в вашем классе Demo.

B<A> c = new B<>(doesNotImplCloneable);   // Gives a compilation error.

Так что, если вы используете метод клонирования Объекта, как я показал здесь, extends/implements Cloneable - это путь.

...