リフレクションを通じて内部クラス オブジェクトを構築します
まず、javalang パッケージの下に内部クラスを含むクラスを作成します。
package javalang; public class Outer { public static class Inner1{} }
このクラスは public static であることに注意してください。これらの修飾子は後で徐々に削除します。
リフレクションを通じて Inner1 オブジェクトを作成するには、まず Inner1 の Class オブジェクトを取得する必要があります。アウターに main メソッドを書きます:
public class Outer { public static class Inner1{} public static void main(String[] args) { System.out.println(Inner1.class); } }
出力結果:
class javalang.Outer$Inner1
次に、クラス名が正しいかどうかを確認します:
public static void main(String[] args) throws Exception { System.out.println(Class.forName("javalang.Outer$Inner1")); }
実行します、はい。あとはそれを使ってオブジェクトを作成するだけです。オブジェクトの作成はコンストラクターに依存します。このクラスにはコンストラクター メソッドがありますか?次のように書くことができます:
public static void main(String[] args) throws Exception { System.out.println(Class.forName("javalang.Outer$Inner1").getConstructors().length); }
それを実行して 1 を出力します。あるみたいですね。次に、この構築メソッドがどのようなものかを見てみましょう:
public static void main(String[] args) throws Exception { System.out.println(Class.forName("javalang.Outer$Inner1").getConstructors()[0]); }
出力結果: public javalang.Outer$Inner1()。これがデフォルトの構築方法です。したがって、次のように書くことができます:
public static void main(String[] args) throws Exception { System.out.println(Class.forName("javalang.Outer$Inner1") .getConstructors()[0].newInstance(); }
出力結果: javalang.Outer$Inner1@ca0b6.これは、実行が成功したことを示します。
次に、Inner のパブリック キーワードを削除して、再度実行します。結果はエラーでした:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
これは、構築メソッドが見つからなかったことを意味します。本当にありません? main メソッドを元に戻します:
public static void main(String[] args) throws Exception { System.out.println(Class.forName("javalang.Outer$Inner1") .getConstructors().length); }
出力結果: 0。本当にコンストラクターがないのでしょうか?いや、実は施工方法が非公開なだけなんです。現時点では、getDeclaredConstructors() を使用して次を取得する必要があります:
public static void main(String[] args) throws Exception { System.out.println(Class.forName("javalang.Outer$Inner1") .getDeclaredConstructors().length); }
出力結果: 1。これで構築方法が決まります。次に、このコンストラクターを呼び出し続けます:
public static void main(String[] args) throws Exception { System.out.println(Class.forName("javalang.Outer$Inner1") .getDeclaredConstructors()[0].newInstance()); }
出力結果: javalang.Outer$Inner1@ca0b6。これで、リフレクションを使用して非パブリック内部クラスのオブジェクトを構築できるようになりました。
次に、静的キーワードを削除しましょう。このとき、次のエラーが報告されました:
Exception in thread "main" java.lang.IllegalArgumentException: 引数の数が間違っています
これはどういう意味ですか?呼び出し時にパラメータを渡しておらず、パラメータの数が間違っているというエラー内容でした。では、このコンストラクターにはどのようなパラメーターがあるのでしょうか?コードを変更して見てみましょう:
public static void main(String[] args) throws Exception { System.out.println(Class.forName("javalang.Outer$Inner1") .getDeclaredConstructors()[0]); }
出力結果: javalang.Outer$Inner1(javalang.Outer)
コンストラクターにはアウター型パラメーターが必要であることがわかります。これは簡単です:
public static void main(String[] args) throws Exception { System.out.println(Class.forName("javalang.Outer$Inner1") .getDeclaredConstructors()[0].newInstance(new Outer())); }
出力結果:
javalang.Outer$Inner1@ca0b6
OK、それだけです。非静的内部クラスにはデフォルトの構築メソッドがないようで、構築中に外部クラスのインスタンスをパラメータとして渡す必要があります。
Java: オブジェクトにアクセスする方法
Java 初心者にとって頭の痛い問題は、オブジェクトをメソッド変数として定義するかメンバー変数として定義するかをどのように決めるかということです。
初心者は最初はこれを気にしません。しかし、書かれたプログラムがますます大きくなり、クラスが増えると、この種の悩みも生じます。
しかし、私がここで書きたいのは、いつでもアクセスできるようにオブジェクトを好きなように配置する方法です。これをマスターすれば、オブジェクトを配置する場所を自由に決めることができます。
ここに簡単な例を示します:
public class AccessingObject { public static void main(String[] args) { Date date = new Date(); } // 获得 date 对象一小时后的时间 private static void anHourLater() { // 这里如何获得 main() 方法中的 date 变量? } }
anHourLater() メソッドで説明したように、1 時間後の日付を取得したいとします。どうやってするの?以下にいくつかの方法があります。
(1) パラメータの受け渡し
public class AccessingObject { public static void main(String[] args) { Date date = new Date(); anHourLater(date); } // 获得 date 对象一小时后的时间 private static void anHourLater(Date d) { Date anHourLater = new Date(d.getTime() + 3600000); } }
(2) メンバーとして定義。メンバーにはすべてのメソッドからアクセスでき、メンバーの初期化はメンバーが定義されている場所または任意のメソッド内に配置できます。
public class AccessingObject { private static Date date; public static void main(String[] args) { date = new Date(); anHourLater(); } // 获得 date 对象一小时后的时间 private static void anHourLater() { Date anHourLater = new Date(date.getTime() + 3600000); } }
(3) 別のクラスに置きます。次の例では、AccessingObject クラスだけでなく、同じパッケージ内のすべてのクラスから DateHolder.date にアクセスできます。
public class AccessingObject { public static void main(String[] args) { DateHolder.date = new Date(); } // 获得 date 对象一小时后的时间 private static void anHourLater() { Date anHourLater = new Date(DateHolder.date.getTime() + 3600000); } } class DateHolder { public static Date date; }
これら 3 つの例を比較すると、最初の 2 つはクラス内でのみ使用でき、比較的安全です。このオブジェクトが他のクラスによって直接変更されることを望まない場合は、3 番目のメソッドを使用しないでください。
最初のメソッドと 2 番目のメソッドの違いは、オブジェクトがメソッド内でのみ使用されている場合、メソッドの実行時にオブジェクトを簡単にリサイクルできることです (すぐにはリサイクルされないことに注意してください)。クラスのメンバーとして定義されている場合、オブジェクトは、それが配置されているクラスがリサイクルされた後にのみリサイクルされます。明らかに、最初の方法が最もリソースを節約できるので、最初の方法を使用するようにしてください。
これら 3 つの例を振り返ると、anHourLater() メソッドで取得した 1 時間後の時刻を main() メソッドで取得したい場合、対応するメソッドもいくつかあります。最後の 2 つの例を変更する必要はありません。最初の例では、日付オブジェクトに直接アクセスできます。次の 2 つの変更メソッドがあります:
(1) を戻り値として
public class AccessingObject { public static void main(String[] args) { Date date = new Date(); Date anHourLater = anHourLater(date); } // 获得 date 对象一小时后的时间 private static Date anHourLater(Date d) { return new Date(d.getTime() + 3600000); } }
(2)パラメータを変更する 内容
public class AccessingObject { public static void main(String[] args) { Date date = new Date(); anHourLater(date); } // 获得 date 对象一小时后的时间 private static void anHourLater(Date d) { d.setTime(d.getTime() + 3600000); } }
2 番目のメソッドは、他の人の物に気軽に触れるのは間違っているので、メソッドの呼び出し元がそれを好むかどうかはわかりません。
Java で内部クラス オブジェクトを構築し、オブジェクトにアクセスする方法を説明するその他の記事については、PHP 中国語 Web サイトに注目してください。