序文
Javaでは、オブジェクトを使用する前に正しく初期化する必要があります。これは、Java仕様によって規定されています。最近、私は興味深い質問を発見しました、そして、この質問に対する答えは一見私の目をだましました。これらの3つのカテゴリをご覧ください。
パッケージcom.ds.test; public class upper {string upperstring; public upper(){initializer.initialize(this); }}パッケージcom.ds.test; public class rownes extends upper {string lowerstring = null; public lower(){super(); system.out.println( "upper:" + upperstring); System.out.println( "lower:" + lowerstring); } public static void main(final string [] args){new lower(); }}パッケージcom.ds.test; public class initializer {static void initialize(final anuper anupper){if(anupper instance of lower){lower lower =(lower)anupper; lower.lowerstring = "loseinited"; } anupper.upperstring = "upperinited"; }} Lowerクラスを実行することで、どのような出力を取得できますか?この最小限の例では、全体の状況をより簡単に見ることができますが、この状況は現実に起こり、人をそらすコードがたくさんあります。
とにかく、出力は次のようです:
アッパー:upperinitedlower:null;
Stringタイプは小さな例で使用されていますが、 Initializerクラスの実際のコードには登録用の代表的なオブジェクトがあります。これはLowerクラスの関数と同じです - 少なくともLowerクラスは意図です。しかし、何らかの理由で、アプリケーションを実行するときは機能しません。代わりに、デフォルトのパスが使用され、デリゲートオブジェクトが設定されていません(null)。
次に、 Lowerのコードを少し変更します。
パッケージcom.ds.test; public class lown extends upper {string lowerstring; public lower(){super(); system.out.println( "upper:" + upperstring); System.out.println( "lower:" + lowerstring); } public static void main(final string [] args){new lower(); }}出力は次のようになりました:
アッパー:supperinitedlower:lowerinited
コードの違いを見つけましたか?
はい、このlowerStringフィールドは、明示的に空に設定されなくなりました。なぜこれが違うのですか?とにかく、参照型フィールドのデフォルト値(ここのStringなど)は空ではありませんか?もちろんそれは空です。このわずかな変化は明らかにコードの動作を何らかの形で変えることはありませんが、結果が異なることがわかります。
それで、正確に何が起こったのですか?初期化順序をチェックすると、すべてが明らかになります。
1。 main()関数は、 Lowerコンストラクターを呼び出します。
2。 Lowerの準備ができています。つまり、すべてのフィールドが作成され、デフォルト値で満たされていることを意味します。たとえば、参照タイプのデフォルト値は空であり、ブール型のデフォルト値はfalseです。現時点では、フィールドへのインライン割り当ては発生しません。
3.親クラスコンストラクターが呼び出されます。これは、言語の特性によって強制されます。したがって、他に何かが起こる前に、アッパーのコンストラクターが呼び出されます。
4.Apperこのコンストラクターは、初期Initializer.initialize()メソッド。
5. Initializerクラスは、新しい文字列を2つのフィールド( upperStringとlowerString )に添付します。インスタンスチェックの少し汚れたinstanceofを使用してこれらの2つのフィールドに値を割り当てることは、特に優れたデザインパターンではありませんが、機能しないでください。心配しないでください。それが起こると、 upperStringとlowerStringへの参照はもはや空になりません。
6. Initializer.initialize()の呼び出しが完了し、 Upperコンストラクターも完了します。
7.今、それは興味深いものになっています: Lowerインスタンスの構築は続きます。 =null割り当てがlowerStringフィールド宣言で明示的に指定されていないと仮定すると、 Lowerコンストラクターは実行を再開し、フィールドに接続された2つの文字列を印刷します。
ただし、NULLを明示的に割り当てる操作がある場合、実行プロセスはわずかに異なります。親クラスコンストラクターが完了すると、コンストラクターの残りの部分が実行される前に可変初期化が実行されます(Java言語仕様のセクション12.5を参照)。この場合、 lowerStringに割り当てられた文字列参照は、以前にnullを再度割り当てられません。その後、残りの関数構造を実行し続け、 lowerStringの値をnullとして印刷します。
これは、オブジェクトの作成に関する詳細(またはJavaコーディング仕様、印刷またはオンラインでチェックする場所を知る)に注意を促すだけでなく、このような初期化を書くことが悪い理由を示すために、私たちの注意を促進するためだけでなく、素晴らしい例です。アッパーのサブクラスはまったく気にしてはなりません。逆に、何らかの理由で特定のフィールドの初期化をサブクラス自体で実行できない場合、独自の初期化ヘルパークラスのバリアントのみが必要です。この場合、 String lowStringまたはString lowerString = null使用する場合、実際には違いはありません。
要約します
上記は、この記事のコンテンツ全体です。この記事の内容が、皆の勉強や仕事に役立つことを願っています。ご質問がある場合は、メッセージを残してコミュニケーションをとることができます。