6

直感的に言えば、Java のコンストラクターはオブジェクトを作成するものであり、コンストラクターが戻るまでそのオブジェクトには何も触れられないと思っていました。ただし、これについて何度も何度も間違っていることが証明されています。

  1. 初期化されていないオブジェクトは、共有によってリークされる可能性がありますthis
  2. 初期化されていないオブジェクトは、ファイナライザーからアクセスするサブクラスによってリークされる可能性があります
  3. 初期化されていないオブジェクトは、完全に構築される前に別のスレッドにリークされる可能性があります

これらの事実はすべて、コンストラクターとは何かという私の直感に反しています。

コンストラクターが Java で実際に何をするのか、またはコンストラクターが何のために使用されることになっているのか、自信を持って言うことはできません。すべての final フィールドを持つ単純な DTO を作成している場合、コンストラクターの使用法を理解できます。これは、変更できないことを除いて、C の構造体とまったく同じであるためです。それ以外では、Java でどのコンストラクターを確実に使用できるのか見当がつきません。それらは単なるコンベンション/シンタックスシュガーですか? (つまり、オブジェクトを初期化するファクトリしかない場合はX x = new X()、 のみを使用し、各フィールドを変更xしてデフォルト値以外の値を設定します。上記の 3 つの事実を考えると、これは実際の Java とほぼ同じです)

コンストラクターによって実際に保証されている 2 つのプロパティを挙げることができます。そうすると、それが のインスタンスであるが のサブクラスではないX x = new X()ことがわかり、最終フィールドは完全に初期化されます。あなたは、 finishedのコンストラクターを知っていて、有効なオブジェクトを持っていると言いたくなるかもしれませんが、別のスレッドに渡す場合、これは真実ではありません。ファクトリの呼び出しの保証)。コンストラクターが実際に保証する他のプロパティは何ですか?xXXXX

4

4 に答える 4

1

JLS セクション 12.5から:

12.5. 新しいクラス インスタンスの作成

新しく作成されたオブジェクトへの参照が結果として返される直前に、指定されたコンストラクターが処理され、次の手順を使用して新しいオブジェクトが初期化されます。

コンストラクターの引数を、このコンストラクター呼び出し用に新しく作成されたパラメーター変数に割り当てます。

このコンストラクターが、(this を使用して) 同じクラス内の別のコンストラクターの明示的なコンストラクター呼び出し (§8.8.7.1) で始まる場合、引数を評価し、これらの同じ 5 つの手順を使用してそのコンストラクター呼び出しを再帰的に処理します。そのコンストラクターの呼び出しが突然完了すると、このプロシージャは同じ理由で突然完了します。それ以外の場合は、ステップ 5 に進みます。

このコンストラクターは、(this を使用して) 同じクラス内の別のコンストラクターの明示的なコンストラクター呼び出しで開始されません。このコンストラクターが Object 以外のクラス用である場合、このコンストラクターは、(super を使用して) スーパークラス コンストラクターの明示的または暗黙的な呼び出しから開始します。これらの同じ 5 つの手順を使用して、引数を評価し、そのスーパークラス コンストラクター呼び出しを再帰的に処理します。そのコンストラクターの呼び出しが突然完了すると、このプロシージャは同じ理由で突然完了します。それ以外の場合は、ステップ 4 に進みます。

このクラスのインスタンス初期化子とインスタンス変数初期化子を実行し、インスタンス変数初期化子の値を対応するインスタンス変数に割り当てます。この順序は、クラスのソース コードにテキストで表示される左から右の順序です。これらの初期化子のいずれかを実行すると例外が発生した場合、それ以上の初期化子は処理されず、このプロシージャは同じ例外で突然終了します。それ以外の場合は、ステップ 5 に進みます。

このコンストラクターの残りの本体を実行します。その実行が突然完了した場合、このプロシージャは同じ理由で突然完了します。それ以外の場合、この手順は正常に完了します。

**

C++ とは異なり、Java プログラミング言語は、新しいクラス インスタンスの作成中にメソッド >dispatch の変更された規則を指定しません。>初期化されるオブジェクトのサブクラスでオーバーライドされるメソッドが呼び出される場合、新しいオブジェクトが完全に初期化される前であっても、これらのオーバーライドするメソッドが使用されます。

そしてJLS 16.9から:

V がインスタンス変数初期化子の前で確実に未割り当てであると結論付けることができる規則はないことに注意してください。C のインスタンス変数初期化子の前で V が確実に割り当て解除されているわけではないと非公式に結論付けることができますが、そのような規則を明示的に述べる必要はありません。

17.4.5 より前に発生:

スレッド 17.5.2 :

そのオブジェクトを構築するスレッド内のオブジェクトの最終フィールドの読み取りは、通常の先行発生規則によって、コンストラクター内のそのフィールドの初期化に関して順序付けられます。コンストラクターでフィールドが設定された後に読み取りが発生した場合、最後のフィールドに割り当てられた値が認識されます。それ以外の場合は、既定値が認識されます。

于 2013-05-20T15:40:38.570 に答える
0

クラスには、クラスの設計図からオブジェクトを作成するために呼び出されるコンストラクターが含まれています。

これは、オラクルがコンストラクターについて述べていることです。

今あなたのポイントに。

直観的に言えば、Java のコンストラクターはオブジェクトを作成するものであり、そのコンストラクターが戻るまで、そのオブジェクトに触れることはできません。

したがって、公式ドキュメントによると、あなたの仮定は正しくありません。そして、意識的12オブジェクトをリークしたい場合を除いて、Java のルールと動作を乱用することが重要です。にも関係がないのでConstructor、これらの点については説明を省略します。

マルチスレッド環境では、 「適切に同期されたブロック」または 「アトミック命令」でない限り、コードの一貫性について3rd保証できるものは何もありません。オブジェクトの作成は命令でもなければ、一貫性があるという保証はありません! それでできることは何もありません。つまり、オブジェクトを作成する責任はありません。synchronizedatomicConstructorConstructoratomic

さて、 「コンストラクターが実際に保証する他のプロパティは何ですか?」という質問に対する答えです。やや簡単です。Constructorsクラスの設計図からオブジェクトを作成する際に呼び出される特別なタイプのメソッドにすぎません。したがって、他のメソッドのように一貫して実行される機会を与えない限り、何も保証できません。一貫して実行された後、オブジェクトが必要に応じて作成および初期化され、その中で指示されたことを保証できます。

于 2013-05-20T16:55:12.480 に答える