Как использовать тип Cloneable в качестве параметра универсального класса Java - PullRequest
3 голосов
/ 22 марта 2011

У меня есть универсальный класс, который должен иметь возможность клонировать объекты типа параметра.Очень простой пример ниже.Компилятор утверждает, что clone () из типа Object не отображается.

public class GenericTest<T extends Cloneable>
    {
    T obj;
    GenericTest(T t)
        {
        obj = t;
        }
    T getClone()
        {
        // "The method clone() from the type Object is not visible."
        return (T) obj.clone();
        }
    }

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

Есть ли способ обойти это или это еще один из тех случаев, когда дизайнерыJava считают рационализацию своих недостатков эквивалентом отсутствия?

Ответы [ 3 ]

6 голосов
/ 22 марта 2011

Поскольку метод помечен как protected в классе Object, вы вообще не можете вызывать этот метод для произвольных объектов. Лично я не думал, что это поначалу будет проблемой (эй, я подкласс Object, поэтому я должен иметь возможность вызывать его защищенные методы, верно?), Но компилятор должен знать, что вы ' является подклассом класса целевого объекта (или в его пакете) для вызова защищенных методов, ни один из которых здесь не применим.

Идея метода clone() состоит в том, что классы, которые его поддерживают, переопределяют метод, объявляя его public.

Единственное реальное решение, которое сохраняет полную функциональность, - это использование отражения для доступа к методу и обхода модификаторов доступа. Альтернативой может быть написание собственного MyCloneable интерфейса, в котором объявлен public clone() метод; это может сработать, если вы когда-либо будете передавать только свои собственные доменные классы, но это означает, что вы не можете использовать его на внешних классах (таких как java.util.String или java.util.ArrayList), поскольку вы не можете заставить их реализовать свой класс. интерфейс.

Согласно ответам на связанный вопрос , это очень сомнительный дизайн.

2 голосов
/ 23 марта 2011

Ошибка со стороны Java. Отражение - верный путь

static Method clone = Object.class.getMethod("clone"); 

static public <T extends Cloneable> 
T clone(T obj)
    return (T) clone.invoke(obj);
0 голосов
/ 08 февраля 2013

Мне нужно было клонировать POJO с полями в нем. То, что сработало, было следующим:

public static Object clone(Object o)
{
  Object clone = null;

  try
  {
     clone = o.getClass().newInstance();
  }
  catch (InstantiationException e)
  {
     e.printStackTrace();
  }
  catch (IllegalAccessException e)
  {
     e.printStackTrace();
  }

  // Walk up the superclass hierarchy
  for (Class obj = o.getClass();
    !obj.equals(Object.class);
    obj = obj.getSuperclass())
  {
    Field[] fields = obj.getDeclaredFields();
    for (int i = 0; i < fields.length; i++)
    {
      fields[i].setAccessible(true);
      try
      {
        // for each class/suerclass, copy all fields
        // from this object to the clone
        fields[i].set(clone, fields[i].get(o));
      }
      catch (IllegalArgumentException e){}
      catch (IllegalAccessException e){}
    }
  }
  return clone;
}
...