Новый экземпляр объекта, на который ссылается интерфейс в Java

63
8

Я работаю над проектом JDK6.

У меня есть pojo, как:

public class MyPojo implements serializable {
private List<Integer> ids;

public List<Integers> getIds() {
return ids;
}

public List<Integers> setIds(List<Integer> ids) {
// idsCopy = copy of ids; // how can I do it?
this.ids = idsCopy;
}
}

Я хотел бы сохранить копию ids параметров, переданных в установщик, но я не хочу специализировать ее в setId метода setId, объявив ссылку как конкретную реализацию интерфейса List: в зависимости от того, где находится pojo используется, ids могут быть либо LinkedList, либо ArrayList и т.д.

Я хотел бы сохранить ту же реализацию параметра ids.

Как я могу сделать копию?

Первым делом я подумал: ids.getClass().newInstance(), но он должен быть окружен блоком try/catch для InstantiationException и IllegalAccessException, в частности потому, что я не уверен, что в реальной реализации ids есть пустая конструктор. Есть ли что-то более непосредственное?

спросил(а) 2021-01-25T13:16:18+03:00 4 месяца, 4 недели назад
1
Решение
63

Как вы сами сказали:

Первым делом я подумал: ids.getClass(). NewInstance(), но он должен быть окружен блоком try/catch для InstantiationException и IllegalAccessException, в частности потому, что я не уверен, что в реальной реализации идентификаторов есть пустая конструктор Есть ли что-то более непосредственное?

Как вы сможете создать экземпляр базового класса, когда вы даже не знаете, как выглядит конструктор? Скажем, поразмыслив, вы знаете, как выглядит (может быть более одного) конструктор, вам все равно придется беспокоиться о таких вещах, как:

    Приватное против внутреннего против публичного - как вы справляетесь с каждым делом? Некоторые реализации List такие как найденные в библиотеке guava, используют шаблон builder для создания коллекции и, таким образом, делают конструктор закрытым. Количество аргументов конструктора - Если их больше одного, как вы строите остальные? Исключения, которые выдает конструктор - как вы их всех ловите? Не говорите "поймать Exception ", потому что вы можете пропустить Throwable. Несколько конструкторов - Как вы решаете, какой из них вызывать? Еще много угловых случаев, чтобы иметь дело с...

Вы должны принять ПОЦЕЛУЙ (K EEP I т S реали S oldier) принцип, а также SoC (S eperation о т C oncerns) принцип. Сохраняйте это простым, и вы будете вознаграждены. Пусть человек, использующий Pojo, решит, как он хочет получить список. До тех пор, пока вы ясно даете понять (посредством документации), что делает метод, пользователь должен принимать рациональные решения относительно того, как он использует этот метод.

Если они делают что-то вроде:

LinkedList<Integer> myIds = ...;
myPojo.setIds(myIds);

затем пусть они решают, как получить идентификаторы, они могут либо привести тип возвращаемого значения, либо сделать копию.

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

ответил(а) 2021-01-25T13:16:18+03:00 4 месяца, 4 недели назад
46

Есть ли что-то более непосредственное?

Есть два возможных способа сделать это:

    Предложенный вами метод: используйте отражение, чтобы вызвать конструктор без аргументов, создайте новый пустой список, а затем используйте List::addAll чтобы скопировать элементы в новый список.

    Используйте метод Object::clone для создания копии.

Любой подход (если он работает!) Создаст объект списка того же типа, что и оригинал. Но ни один из методов не гарантированно работает для всех возможных классов List.

    Рефлексивный подход терпит неудачу, если у класса реализации списка нет пригодного для использования/доступного конструктора без аргументов.

    Подход clone не выполняется, если класс реализации списка не переопределяет Object::clone надлежащим образом.


Обратите внимание, что это не гипотетические проблемы. Класс реализации списка может быть специально разработан для предотвращения клонирования программ списками. Например, может быть некоторая связь между списком и (скажем) набором результатов запроса к базе данных, так что клонирование не имеет смысла.

Но с другой стороны, если разработчик библиотеки не предоставил конструктор без аргументов или переопределение clone, он, вероятно, сделал это по уважительной причине.

Наконец, сомнительно, что вы должны пытаться сделать это вообще. Нет очевидной причины, по которой ваше MyPojo ids классов MyPojo использует тот же класс List что и исходный аргумент. Это фактически делает поведение класса MyPojo зависимым от поведения предоставленного списка. Я бы сказал, что это плохо, потому что вы ослабляете границу абстракции для своего класса MyPojo.

ответил(а) 2021-01-25T13:16:18+03:00 4 месяца, 4 недели назад
45

Вы имеете в виду, как это?

public void setIds(List ids) {
// idsCopy = copy of ids; // how can I do it?
List idsCopy = ids;
this.ids = idsCopy;
}

ответил(а) 2021-01-25T13:16:18+03:00 4 месяца, 4 недели назад
45

Вы можете создать копию List<E> с помощью конструктора ArrayList(Collection<E>).
Как это:

public void setIds(List<Integer> ids) {
List<Integer> idsCopy = new ArrayList<Integer>(ids);
this.ids = idsCopy;
}

ответил(а) 2021-01-25T13:16:18+03:00 4 месяца, 4 недели назад
-4

Вы можете использовать Arrays.asList для этого, например

public void setIds(List<Integer> ids) {
this.ids = Arrays.asList(ids.toArray(new Integer[ids.size()]));
}

это должно работать на Java 1.6

ответил(а) 2021-01-25T13:16:18+03:00 4 месяца, 4 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема