4

クラスがあります

public class MyMain{
    public static void main(String... arg){
            Temp t = new Temp(){
                {
                    System.out.println(" instance initialize");
                }
            };

        }
    }

class Temp{
    int i;

    {
        i=9;
        System.out.println("Static"+i);
    }
    Temp(){
        System.out.println("Temp const "+i);
    }
}

メインメソッドを実行すると、次の出力が表示されます。

Static9
Temp const 9
instance initialize

理想的には、ブロックはコンストラクターの前に実行されますが、インライン初期化ブロックはコンストラクターの後に呼び出されます。なんで?

4

7 に答える 7

16

のサブクラスを作成していますTemp。各クラスでは、コンストラクタ本体の前にインスタンス初期化子が実行されますが、スーパークラスはサブクラスの初期化の前に初期化されます。したがって、実行フローは次のとおりです。

  • の初期化子Object
  • コンストラクタ本体Object
  • の初期化子Temp
  • コンストラクタ本体Temp
  • 匿名クラスの初期化子
  • 匿名クラスのコンストラクタ本体 (なし)

とにかく、このように見えるコードはすべてリファクタリングすることを強くお勧めします-賢さよりも明快さを目指してください。

于 2012-05-21T16:51:07.130 に答える
6

JLS 12.5は、建設中に物事が起こる順序を綴っています(私のものを強調してください):

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

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

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

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

要約すると、スーパークラス コンストラクター (手順 3) は、インスタンス初期化子 (手順 4) の前に実行されます。どちらも「このコンストラクターの残りの部分」の前に実行されます (例にはありません)。

于 2012-05-21T16:52:09.117 に答える
2

あなたのコードで

Temp t = new Temp(){
    {
        System.out.println(" instance initialize");
    }
};

Tempクラスを拡張する匿名クラスのオブジェクトを作成しています。

サブクラスのオブジェクトの作成:

initialize block from Superclass
constructor of Superclass
initialize block from Subclass
constructor of Subclass
于 2012-05-21T17:07:41.483 に答える
2

実際に作成しているのは、Tempクラス インスタンスではなく、 から継承する無名クラスのインスタンスですTemp

したがって、最初にTemp初期化子 (無名ブロック内Tempとそのコンストラクター) が呼び出され、その後、無名クラスの初期化子が呼び出されます。

于 2012-05-21T16:53:46.967 に答える
2

インライン初期化ブロックは、現在インスタンス化している匿名クラスの基本クラスのコンストラクターの後、匿名クラス自体の空の暗黙的なコンストラクターの前に呼び出されます。

于 2012-05-21T16:52:00.740 に答える
1

ポイント 1: 明確にするために、2 つのインスタンス初期化子があります。1 つは Temp クラスにあり、もう 1 つは、Temp のサブクラスである main() メソッドで作成された匿名内部クラスにあります。

ポイント 2: インスタンス初期化子は実際にはコンストラクターの前に実行されません。JLS によると、それらはコンストラクターの実行中スーパー コンストラクターに委譲した後、インスタンス フィールドを初期化してコンストラクターを完了する前に実行されます。

ポイント 3: コードでは、各初期化子が適切なタイミングで正しく実行されます。2 番目のものは最初のものと同時に実行されることを期待していると思いますが、ポイント 1 で指摘したように、それらは 2 つの異なるクラスの初期化子であるため、それは正しくありません。

ポイント 4: 静的初期化子とインスタンス初期化子の間で混乱することもあります。それらは2つの異なるものです。

于 2012-05-21T16:58:17.947 に答える
0

オブジェクトは、他の操作を行う前に、最初にメモリ内に存在する必要があります。オブジェクトはメモリ内に構築され、コンソールに出力されます。

于 2012-05-21T16:49:26.330 に答える