引数なしのコンストラクターは要件です(Hibernateのようなツールは、このコンストラクターでリフレクションを使用してオブジェクトをインスタンス化します)。
私はこの手の波状の答えを得ましたが、誰かがさらに説明できますか?ありがとう
引数なしのコンストラクターは要件です(Hibernateのようなツールは、このコンストラクターでリフレクションを使用してオブジェクトをインスタンス化します)。
私はこの手の波状の答えを得ましたが、誰かがさらに説明できますか?ありがとう
Hibernate、およびリフレクションを介してオブジェクトを作成する一般的なコードを使用Class<T>.newInstance()
して、クラスの新しいインスタンスを作成します。このメソッドでは、オブジェクトをインスタンス化できるようにするために、パブリックの引数なしコンストラクターが必要です。ほとんどのユースケースでは、引数なしのコンストラクターを提供することは問題ではありません。
シリアル化ではjvmマジックを使用してコンストラクターを呼び出さずにオブジェクトを作成するため、シリアル化に基づくハックがあり、引数なしのコンストラクターがないことを回避できます。ただし、これはすべてのVMで利用できるわけではありません。たとえば、XStreamは、パブリックの引数なしコンストラクターを持たないオブジェクトのインスタンスを作成できますが、特定のVMでのみ使用可能ないわゆる「拡張」モードで実行することによってのみ作成できます。(詳細については、リンクを参照してください。)Hibernateの設計者は、すべてのVMとの互換性を維持することを確実に選択したため、このようなトリックを回避し、Class<T>.newInstance()
引数なしのコンストラクターを必要とする公式にサポートされているリフレクション方式を使用します。
えーと、皆さんごめんなさい、でもHibernateは、クラスにパラメーターのないコンストラクターが必要なわけではありません。JPA 2.0仕様ではそれが要求されており、これはJPAに代わって非常に不十分です。JAXBのような他のフレームワークもそれを必要としますが、これもそれらのフレームワークに代わって非常に不十分です。
(実際、JAXBはエンティティファクトリを許可すると思われますが、これらのファクトリをそれ自体でインスタンス化することを主張し、パラメータなしのコンストラクタを必要とします。これは、私の本では、ファクトリを許可しないのとまったく同じです。 !)
しかし、Hibernateはそのようなことを必要としません。
Hibernateはインターセプトメカニズムをサポートしており(ドキュメントの「インターセプター」を参照)、必要なコンストラクターパラメーターを使用してオブジェクトをインスタンス化できます。
基本的に、hibernateをセットアップするときに、インターフェイスを実装するオブジェクトを渡します。その後、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以外のツールの質問の「理由」の部分に答えるには、答えは「まったく正当な理由がない」であり、これは休止状態のインターセプターの存在によって証明されます。クライアントオブジェクトのインスタンス化のための同様のメカニズムをサポートしている可能性のあるツールはたくさんありますが、サポートしていないため、オブジェクトを自分で作成するため、パラメーターなしのコンストラクターが必要です。これらのツールの作成者は、無知なアプリケーションプログラマーが使用する魔法に満ちたフレームワークを作成する忍者システムプログラマーであると考えているため、これが起こっていると信じたくなります。 ...ファクトリパターンなどの高度な構造の必要性。(わかった、そう思う。私は実際にはそうは思いません。私は冗談を言っています。)
Hibernateはオブジェクトをインスタンス化します。したがって、それらをインスタンス化できる必要があります。引数のないコンストラクターがない場合、Hibernateはそれをインスタンス化する方法、つまり渡す引数を知りません。
Hibernateのドキュメントには次のように書かれています。
4.1.1。引数なしのコンストラクターを実装する
Hibernateがを使用してそれらをインスタンス化できるように、すべての永続クラスにはデフォルトのコンストラクター(非公開にすることができます)が必要Constructor.newInstance()
です。Hibernateでランタイムプロキシを生成するために、少なくともパッケージの可視性を備えたデフォルトのコンストラクターを用意することをお勧めします。
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>);
Personオブジェクトを取得するためにHibernateが呼び出す必要があるコンストラクターはどれですか?見えますか?
2ºそして最後に、リフレクションを使用することで、Hibernateは引数なしのコンストラクターを介してクラスをインスタンス化できます。だからあなたが電話するとき
Person person = (Person) session.get(Person.class, <IDENTIFIER>);
Hibernateは次のようにPersonオブジェクトをインスタンス化します
Person.class.newInstance();
APIドキュメントによると
クラスは、空の引数リストを持つ新しい式のようにインスタンス化されます
この話の教訓
Person.class.newInstance();
と類似しています
new Person();
他には何もありません
Hibernateはクエリの結果として(リフレクションを介して)インスタンスを作成する必要があります。Hibernateはそのためにエンティティのno-argコンストラクターに依存しているため、no-argコンストラクターを提供する必要があります。はっきりしないことは何ですか?
実際には、0引数のコンストラクターを持たないクラスをインスタンス化できます。クラスのコンストラクターのリストを取得し、1つを選択して、偽のパラメーターを使用して呼び出すことができます。
これは可能であり、問題なく機能すると思いますが、それはかなり奇妙なことに同意する必要があります。
Hibernateの方法(0引数のコンストラクターを呼び出し、Reflectionを介してインスタンスのフィールドを直接変更する可能性があります。セッターの呼び出し方法を知っている可能性があります)でオブジェクトを構築する方法は、オブジェクトの構築方法に少し反します。 Java-新しいオブジェクトが目的のオブジェクトになるように、適切なパラメーターを使用してコンストラクターを呼び出します。オブジェクトをインスタンス化してから変更することは、いくぶん「反Java」(または、反純粋な理論的Java)であると私は信じています。そして間違いなく、直接フィールド操作を介してこれを行うと、カプセル化とそのすべての凝ったカプセル化のものになります。
これを行う適切な方法は、Hibernateマッピングで、適切なコンストラクターを使用してデータベース行の情報からオブジェクトをインスタンス化する方法を定義することだと思います...しかし、これはより複雑になります。つまり、両方のHibernateが均等になります。より複雑になると、マッピングはより複雑になります...そしてすべてがより「純粋」になります。そして、これが現在のアプローチよりも有利になるとは思いません(「適切な方法」で物事を行うことに満足していることを除いて)。
そうは言っても、Hibernateのアプローチはあまり「クリーン」ではないことを考えると、0引数のコンストラクターを持つ義務は厳密には必要ありませんが、純粋に「適切な方法で」行われたと思いますが、要件はある程度理解できます。 「根拠、彼らが「適切な方法」から(合理的な理由ではあるが)それよりずっと前に逸脱したとき。
名前/名前の競合、コンストラクター内の未定義のロジックを変更して、パラメーター化されたコンストラクターの任意のパラメーターにデータを一致させようとするよりも、リフレクションを介してパラメーターなしのコンストラクターを使用してオブジェクトを作成し、リフレクションを介してそのプロパティをデータで埋める方がはるかに簡単です。オブジェクトなどのプロパティと一致しないパラメータセット。
多くのORMとシリアライザーは、パラメーターなしのコンストラクターを必要とします。これは、リフレクションによるパラメーター化されたコンストラクターは非常に壊れやすく、パラメーターなしのコンストラクターは、アプリケーションの安定性と開発者のオブジェクト動作の制御の両方を提供するためです。
Hibernateは遅延読み込みにプロキシを使用します。コンストラクターを定義しないか、プライベートにしない場合でも、プロキシメカニズムに依存しないものが機能する可能性があります。たとえば、クエリAPIを使用してオブジェクトを(コンストラクターなしで)直接ロードします。
ただし、session.load method()を使用すると、コンストラクターが使用できないため、プロキシジェネレーターlibから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はProjectインスタンスとは独立してProjectPKをインスタンス化する必要があるため、ProjectPKは静的内部クラスであるか、独自の.javaファイルで宣言されている必要があります。
私の場合、引数なしのコンストラクターを非表示にする必要がありましたが、Hibernateのために非表示にできませんでした。そこで、別の方法で問題を解決しました。
/**
* @deprecated (Hibernate's exclusive constructor)
*/
public ObjectConstructor (){ }
以下の要約。JPAと互換性があるか、厳密にHibernateになりたいかは重要です
公式ドキュメントをご覧ください:https ://docs.jboss.org/hibernate/orm/5.6/userguide/html_single/Hibernate_User_Guide.html#entity-pojo
セクション2.1JPA2.1仕様のエンティティクラスは、エンティティクラスの要件を定義します。JPAプロバイダー間での移植性を維持したいアプリケーションは、次の要件に準拠する必要があります。
1つのポイントは言う:
エンティティクラスには、パブリックまたは保護された引数なしのコンストラクタが必要です。追加のコンストラクターも定義できます。
ただし、休止状態はこれではそれほど厳密ではありません。
ただし、Hibernateの要件はそれほど厳密ではありません。上記のリストとの違いは次のとおりです。
1つのポイントは言う:
エンティティークラスには、引数なしのコンストラクターが必要です。コンストラクターは、パブリック、保護、またはパッケージの可視性である可能性があります。追加のコンストラクターも定義できます。
詳細はすぐ下にあります: https ://docs.jboss.org/hibernate/orm/5.6/userguide/html_single/Hibernate_User_Guide.html#entity-pojo-constructor
JPAでは、このコンストラクターをパブリックまたは保護として定義する必要があります。システムSecurityManagerが可視性設定のオーバーライドを許可している限り、Hibernateは、ほとんどの場合、コンストラクターの可視性を気にしません。とはいえ、ランタイムプロキシ生成を活用したい場合は、少なくともパッケージの可視性を使用してコンストラクターを定義する必要があります。