Конструктор без аргументов является требование (такие инструменты, как использование Hibernate отражение этого конструктора объекты-экземпляры).
Я получил этот волнистый ответ, но может ли кто-нибудь объяснить дальше? Благодаря
Конструктор без аргументов является требование (такие инструменты, как использование Hibernate отражение этого конструктора объекты-экземпляры).
Я получил этот волнистый ответ, но может ли кто-нибудь объяснить дальше? Благодаря
Спящий режим и код в целом, который создает объекты через отражение, использует Class<T>.newInstance()
, чтобы создать новый экземпляр ваших классов. Этот метод требует, чтобы публичный конструктор no-arg мог создавать экземпляр объекта. Для большинства случаев использование конструктора no-arg не является проблемой.
Существуют хаки, основанные на сериализации, которые могут работать без создания конструктора no-arg, поскольку сериализация использует jvm magic для создания объектов без вызова конструктора. Но это не доступно для всех виртуальных машин. Например, XStream может создавать экземпляры объектов, у которых нет открытого конструктора no-arg, но только путем запуска в так называемом "так называемый" расширенный" режим, который доступен только на некоторых виртуальных машинах. (Подробнее см. Ссылку). Дизайнеры Hibernate, безусловно, решили поддерживать совместимость со всеми виртуальными машинами и поэтому избегают таких трюков и используют официально поддерживаемый метод отражения Class<T>.newInstance()
, требующий конструктора no-arg.
Спящий режим создает экземпляры объектов. Таким образом, он должен иметь возможность создавать их. Если конструктор no-arg не существует, Hibernate не будет знать, как его создать, то есть какой аргумент передать.
Документация hibernate говорит:
4.1.1. Внесите конструктор без аргументов
У всех постоянных классов должен быть конструктор по умолчанию (который может быть непубличным), так что Hibernate может создавать экземпляры с помощью Constructor.newInstance()
. Рекомендуется, чтобы у вас был конструктор по умолчанию, имеющий хотя бы видимость пакета для генерации прокси-сервера во время работы в Hibernate.
Спящий режим - это структура ORM, которая поддерживает стратегию доступа к полям или свойствам. Однако он не поддерживает построение на основе конструктора - возможно, что бы вы хотели? - из-за некоторых проблем, таких как
1º Что произойдет, если ваш класс содержит много конструкторов
public class Person {
private String name;
private Integer age;
public Person(String name, Integer age) { ... }
public Person(String name) { ... }
public Person(Integer age) { ... }
}
Как вы можете видеть, вы имеете дело с проблемой несогласованности, потому что Hibernate не может предположить, какой конструктор должен быть вызван. Например, предположим, что вам нужно восстановить сохраненный объект Person
Person person = (Person) session.get(Person.class, <IDENTIFIER>);
Какой конструктор должен вызвать вызов Hibernate для извлечения объекта Person? Вы видите?
2º И, наконец, используя рефлексию, Hibernate может создать экземпляр класса через его конструктор no-arg. Поэтому, когда вы вызываете
Person person = (Person) session.get(Person.class, <IDENTIFIER>);
Hibernate будет создавать экземпляр объекта Person следующим образом
Person.class.newInstance();
Что в соответствии с документацией API
Класс создается так, как будто новым выражением с пустым списком аргументов
Мораль истории
Person.class.newInstance();
похож на
new Person();
Больше ничего
Erm, извините всех, но Hibernate не требует, чтобы ваши классы должны иметь конструктор без параметров. Спецификация JPA 2.0 требует этого, и это очень слабо от имени JPA. Другие рамки, такие как JAXB, также требуют этого, что также очень слабое от имени этих фреймворков.
(На самом деле JAXB, предположительно, позволяет предприятиям-основателям, но он настаивает на создании этих фабрик сам по себе, требуя, чтобы у них был какой-то беспредметный конструктор, который в моей книге точно так же хорош, как не позволяет фабрикам, как ламе это!)
Но Hibernate не требует такой вещи.
Hibernate поддерживает механизм перехвата (см. "Interceptor" в документации,), который позволяет вам создавать объекты с любыми параметрами конструктора, которые им нужны.
В основном, что вы делаете, так это то, что при настройке hibernate вы передаете ему объект, реализующий интерфейс org.hibernate.Interceptor
, а спящий режим будет вызывать метод instantiate()
этого интерфейса всякий раз, когда ему нужен новый экземпляр объекта т.е. ваша реализация этого метода может new
ваши объекты так, как вам нравится.
Я сделал это в проекте, и он работает как шарм. В этом проекте я делаю все через JPA, когда это возможно, и я использую только функции Hibernate, такие как перехватчик, когда у меня нет другого выбора.
Hibernate, похоже, несколько не уверен в этом, так как во время запуска он выдает информационное сообщение для каждого из моих классов сущностей, сообщая мне INFO: HHH000182: No default (no-argument) constructor for class
и class must be instantiated by Interceptor
, но затем я делаю их экземпляр перехватчиком, и это доволен этим.
Чтобы ответить на вопрос "почему" в вопросе о инструментах, отличных от Hibernate, ответ "абсолютно без веской причины", и это подтверждается наличием перехватчика спящего режима. Есть много инструментов, которые могли бы поддерживать какой-то аналогичный механизм для создания объектов клиента, но они этого не делают, поэтому они сами создают объекты, поэтому им нужно требовать конструкторы без параметров. У меня возникает соблазн полагать, что это происходит потому, что создатели этих инструментов считают себя программистами ниндзя-систем, которые создают фреймворки, полные магии, которые будут использоваться неосведомленными программистами приложений, которые (так они думают) никогда бы в своих самых смелых мечтах не имели нужны для таких продвинутых конструкций, как... Factory Шаблон. (Хорошо, у меня есть соблазн думать так. На самом деле я так не думаю. Я шучу.)
Собственно, вы можете создавать экземпляры классов, у которых нет конструктора 0-args; вы можете получить список конструкторов класса, выбрать один и вызвать его с фиктивными параметрами.
Пока это возможно, и я думаю, что это сработает и не будет проблематичным, вам придется согласиться с тем, что это довольно странно.
Построение объектов так, как это делает Hibernate (я считаю, что он вызывает конструктор 0-arg, а затем он, вероятно, модифицирует поля экземпляра непосредственно через Reflection. Возможно, он знает, как вызывать сеттеры) немного отличается от того, как объект должен быть построенным в Java - вызвать конструктор с соответствующими параметрами, чтобы новый объект был объектом, который вы хотите. Я считаю, что создание экземпляра объекта, а затем его мутация - это нечто вроде "анти-Java" (или, я бы сказал, анти чистой теоретической Java), и, безусловно, если вы это сделаете с помощью прямых манипуляций с полями, это будет инкапсуляция и все, что причудливо инкапсулирует.
Я думаю, что правильным способом сделать это было бы определение в Hibernate-сопоставлении того, как объект должен быть создан из информации в строке базы данных с использованием соответствующего конструктора... но это было бы более сложным, что означало бы и Hibernate было бы еще более сложным, отображение было бы более сложным... и все было бы более "чистым"; и я не думаю, что это будет иметь преимущество перед текущим подходом (кроме чувства хорошего в том, чтобы делать вещи "надлежащим образом" ).
Сказав это и увидев, что подход Hibernate не очень "чист", обязательство иметь конструктор с 0-arg не является строго необходимым, но я могу немного понять это требование, хотя я считаю, что они сделали это чисто "надлежащим образом", когда они отклонялись от "надлежащего пути" (хотя и по разумным причинам) задолго до этого.
Спящий режим должен создавать экземпляры в результате ваших запросов (через отражение), Hibernate полагается на конструктор объектов no-arg для этого, поэтому вам нужно предоставить конструктор no-arg. То, что не ясно?
Гораздо проще создать объект с помощью конструктора без параметров через отражение, а затем заполнить его свойства данными посредством отражения, чем пытаться сопоставить данные с произвольными параметрами параметризованного конструктора с изменением конфликтов имен/имен, undefined логический внутренний конструктор, набор параметров, не соответствующих свойствам объекта, и т.д.
Многие ORM и сериализаторы требуют конструкторов без параметров, поскольку параметризированные конструкторы через отражение очень хрупкие, а конструкторы без параметров обеспечивают как стабильность приложения, так и контроль над поведением объекта разработчику.
Hibernate использует прокси для ленивой загрузки. Если вы не определяете конструктор или не делаете его закрытым, некоторые вещи могут по-прежнему работать - те, которые не зависят от механизма прокси. Например, загрузка объекта (без конструктора) напрямую с помощью API запросов.
Но если вы используете метод session.load(), вы столкнетесь с InstantiationException из генератора прокси-генератора из-за отсутствия конструктора.
Этот парень сообщил об аналогичной ситуации:
http://kristian-domagala.blogspot.com/2008/10/proxy-instantiation-problem-from.html
Ознакомьтесь с этим разделом спецификации языка Java, который объясняет разницу между статическими и нестационарными внутренними классами: http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.1.3
Статический внутренний класс концептуально не отличается от обычного общего класса, объявленного в .java файле.
Так как Hibernate необходимо инстанцировать ProjectPK независимо от экземпляра Project, ProjectPK либо должен быть статическим внутренним классом, либо объявлен в нем собственный .java файл.
ссылка org.hibernate.InstantiationException: конструктор по умолчанию