前書き
- 世界のすべてに独自の「基盤」があります。木の基礎は根にあり、建物の基礎はフレームにあり、人間であるための鍵は美徳にあり、政府であるための鍵はにあります。実際、ある程度「基本」と「必須」は同じルート、同じブランチと呼ぶことができます。それらは同じことを意味します。そうすれば、「ベース」とは何かを考える必要があるだけではありません。とJavaの「必須」?実際、これは「反省」であると躊躇なく答えることができ、反省の秘密は以下で徐々に明らかにされていきます。
Javaプログラムの実行中のプロセス
- リフレクションを学ぶ前に、まずJavaプログラムを実行するプロセスを学ぶ必要があります。プログラムが特定のクラスを使用する場合、システムは、クラスのロード、クラスの接続、およびクラスの初期化の3つのステップを通じてクラスを初期化します。予期しない状況が発生しない場合、JVMはこれらの3つのステップを継続的に完了します。
クラスの読み込み
クラスのロードとは、クラスファイルをメモリに読み込み、そのクラスのjava.lang.Classオブジェクトを作成することです。クラスが使用されると、システムはそのクラスのjava.lang.Classオブジェクトを作成します。
クラスのロードプロセスは、通常3つのプロセスを経ます。
1.クラスによって定義されたバイナリバイトストリームをその完全修飾名で取得します(get stream)
。2。このバイトストリームによって表される静的ストレージ構造をメソッド領域(メソッド領域)のランタイムデータ構造に変換します。
3. Javaヒープ内のこのクラスを表すjava.lang.Classオブジェクトを、メソッド領域のデータへのアクセスエントリとして生成します(アクセスエントリの生成)。
リンク
リンクは3つのフェーズに分かれています
。1。検証フェーズ:ロードされたクラスが正しい内部構造を持ち、他のクラスと整合性があるかどうかを検証するために使用されます。
2.準備段階:クラス変数にメモリを割り当て、デフォルトの初期化値を設定する責任があります。
3.解析段階:クラスのバイナリデータ内のシンボル参照を直接参照に置き換えます。
検証:
検証はリンクの最初のステップです。この段階の目的は、クラスファイルのバイトストリームに含まれる情報が現在の仮想マシンの要件を満たし、仮想マシン自体のセキュリティを危険にさらさないことを確認することです。検証フェーズでは、検証アクション
ファイル形式の検証の4つのフェーズが大まかに完了します。バイトストリームがクラスファイル形式の仕様を満たしているかどうかを確認します。たとえば、0xCAFEBABEで始まるかどうか、メジャーバージョン番号とマイナーバージョン番号が処理範囲内にあるかどうかを確認します。現在の仮想マシンの定数、定数プール内の定数にサポートされていないタイプがあるかどうか。
メタデータの検証:バイトコードで記述された情報に対してセマンティック分析を実行し(注:javacコンパイル段階でセマンティック分析を比較)、記述された情報がJava言語仕様の要件を満たしていることを確認します。例:java.langを除くこのクラス.Object外部に親クラスがあるかどうか。
バイトコードの検証:データフローと制御フローの分析を通じて、プログラムのセマンティクスが合法で論理的であると判断されます。
シンボル参照の検証:解析アクションを正しく実行できることを確認します。
検証フェーズは非常に重要ですが、必須ではありません。プログラムの実行時間には影響しません。検証が不要な場合は、-Xverifynoneパラメーターを使用して、ほとんどのクラス検証手段をオフにして、仮想マシンのクラスの読み込みを短縮することを検討できます。時間。
初期化
クラスの静的変数に正しい初期値を割り当てます。JVMは、主にクラス変数を初期化するために、クラスの初期化を担当します。Javaでクラス変数を初期化するには、次の2つの方法があり
ます。1。クラス変数の宣言は、初期値を指定することです。
2.静的コードブロックを使用して、クラス変数の初期値を指定します。
クラス初期化またはJVM初期化の手順は次のとおりです
。1)このクラスがロードおよびリンクされていない場合は、最初にロードおよびリンクします
。2)このクラスに直接の親クラスがあり、このクラスが初期化されていない場合(注:クラスローダーでは、クラスは1回だけ初期化できます)、次に親クラスを直接初期化します(インターフェイスには適用されません)
。3)クラスに初期化ステートメント(静的変数や静的ブロックなど)がある場合は、これらを実行します。順番に初期化ステートメント。
Javaクラスローダー
Javaクラスローダーの主な機能は、.classファイルをメモリにロードし、それに対応するjava.lang.Classオブジェクトを生成することです。
JVMクラスローダー
全体的な責任:クラスローダーがクラスのロードを担当する場合、別のクラスローダーを使用してクラスをロードしない限り、クラスが依存して参照する他のクラスもクラスローダーによってロードされます。
親クラスの委任:クラスローダーがクラスのロードを担当する場合、最初に親クラスローダーにクラスのロードを試行させ、親クラスローダーがクラスをロードできない場合にのみ、自身のクラスパスからクラスのロードを試行します。
キャッシュメカニズム:**ロードされたすべてのクラスがキャッシュされるようにします。プログラムがClassオブジェクトを使用する必要がある場合、クラスローダーは最初にキャッシュ領域でクラスを検索します。Classオブジェクトがキャッシュ領域に存在しない場合のみ、その場合にのみ、システムはこのクラスに対応するバイナリデータを読み取り、Classオブジェクトに変換して、バッファに格納します。
Javaの組み込みクラスローダー
ブートストラップクラスローダー:これは仮想マシンの組み込みクラスローダーであり、通常はnullとして表され、親のロードクラスはありません。
プラットフォームクラスローダー:プラットフォームクラスローダーは、すべてのプラットフォームクラスを表示できます。プラットフォームクラスには、プラットフォームクラスローダーまたはその祖先によって定義されたJavaSEプラットフォームAPI、その実装クラス、およびJDK固有のランタイムクラス
システムクラスローダーが含まれます。これは、システムクラスローダーとも呼ばれます。これは、プラットフォームクラスローダーとは異なるアプリケーションクラスローダーです。システムクラスローダーは通常、JDK固有のツール
でアプリケーションクラスパス、モジュールパス、およびクラスクラスローダーの継承関係を定義するために使用されます。システムの親ローダーはプラットフォームであり、プラットフォームの親ローダーはブートストラップです。
反射
リフレクションとは、実行時にクラスの変数とメソッド情報(メンバーメソッドと構築メソッド)を取得することです。次に、取得した情報に基づいてオブジェクトを作成します。これは、メソッドを呼び出すためのメカニズムです。この動的な性質により、プログラムの柔軟性を大幅に向上させることができます。プログラムはコンパイル期間中に決定する必要はなく、実行時にも拡張できます。以下は簡単な反射図です。
実際、接地ガスのわずかな反射は、クラスのさまざまな部分を他のオブジェクトにカプセル化することです
。単純な反射の例の概略図は、
それがStudentクラスであるか、Teacherクラスであるかにかかわらず、実行時の反射メカニズムによって取得されます。これら2つのクラスの情報を取得して、新しいルールオブジェクトを作成します。
ケースナンバーワン
1.プロパティファイルをロードしてリフレクションファイルを構成します。
エンティティクラス
public class Student {
private String username;
private String age;
private String gender;
private String address;
private String phone;
public Student() {
}
public Student(String username, String age,
String gender, String address, String phone) {
this.username = username;
this.age = age;
this.gender = gender;
this.address = address;
this.phone = phone;
}
public String getUsername() {
return username;
}
public Student setUsername(String username) {
this.username = username;
return this;
}
public String getAge() {
return age;
}
public Student setAge(String age) {
this.age = age;
return this;
}
public String getGender() {
return gender;
}
public Student setGender(String gender) {
this.gender = gender;
return this;
}
public String getAddress() {
return address;
}
public Student setAddress(String address) {
this.address = address;
return this;
}
public String getPhone() {
return phone;
}
public Student setPhone(String phone) {
this.phone = phone;
return this;
}
//成员方法:一个私有,四个公共
private void function() {
System.out.println("function");
}
public void method1() {
System.out.println("method");
}
public void method2(String s) {
System.out.println("method:" + s);
}
public String method3(String s, int i) {
return s + "," + i;
}
public void study() {
System.out.println("好好学习天天向上");
}
@Override
public String toString() {
return "Student{" +
"username='" + username + '\'' +
", age='" + age + '\'' +
", gender='" + gender + '\'' +
", address='" + address + '\'' +
", phone='" + phone + '\'' +
'}';
}
}
public class Teacher {
public void teach() {
System.out.println("为国育人");
}
}
テストクラス
public class Demo02Test {
public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, IOException, InstantiationException, NoSuchMethodException, ClassNotFoundException {
ReflectTest();
}
public static void ReflectTest() throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
System.out.println("------------------------------------");
//BufferedReader bufferedReader = new BufferedReader(new FileReader("reflect\\myproperties.properties"));
FileReader fileReader = new FileReader("G:\\javaEE\\javaTEST\\newfeature\\src\\reflect\\myproperties.properties");
Properties properties = new Properties();
properties.load(fileReader);
fileReader.close();
String className = properties.getProperty("className");
String methodName = properties.getProperty("methodName");
Class<?> aClass = Class.forName(className);
Constructor<?> constructor = aClass.getConstructor();
Object o = constructor.newInstance();
Method method = aClass.getMethod(methodName);
method.invoke(o);
System.out.println("---------------------------------");
}
}
プロパティファイル
className=reflect.domain.Teacher
methodName=teach
テスト結果
構成ファイルを変更した後のテスト結果は次のとおりです。
className=reflect.domain.Student
methodName=study
ケース2
学生インスタンスオブジェクトをユーザーインスタンスオブジェクトに送信します。
エンティティクラス
public class User {
private String username;
private String age;
private String gender;
private String address;
private String phone;
public User() {
}
public User(String username, String age,
String gender, String address, String phone) {
this.username = username;
this.age = age;
this.gender = gender;
this.address = address;
this.phone = phone;
}
public String getUsername() {
return username;
}
private User setUsername(String username) {
this.username = username;
return this;
}
public String getAge() {
return age;
}
private User setAge(String age) {
this.age = age;
return this;
}
public String getGender() {
return gender;
}
private User setGender(String gender) {
this.gender = gender;
return this;
}
public String getAddress() {
return address;
}
private User setAddress(String address) {
this.address = address;
return this;
}
public String getPhone() {
return phone;
}
private User setPhone(String phone) {
this.phone = phone;
return this;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", age='" + age + '\'' +
", gender='" + gender + '\'' +
", address='" + address + '\'' +
", phone='" + phone + '\'' +
'}';
}
}
リフレクションツール
public class MyReflectUtils {
public static <T> T MyReflectMethod(HashMap<String ,String> hashMap, Class<T> cls){
T t = null;
try {
t = cls.newInstance();
Field[] declaredFields = cls.getDeclaredFields();
for (Field field:
declaredFields) {
field.setAccessible(true);
System.out.println(field.toString());
}
Method[] methods = cls.getDeclaredMethods();
for (Method method :
methods) {
method.setAccessible(true);
String methodName = method.getName();
if(methodName.startsWith("set")){
String subName = methodName.substring(3);
String firstchar = subName.substring(0, 1);
firstchar=firstchar.toLowerCase();
String actMethodName= firstchar+subName.substring(1);
String value = hashMap.get(actMethodName);
try {
method.invoke(t,value);
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return t;
}
/*public static User MyReflectMethod1(HashMap<String,String> hashMap){
User user = new User();
//获取姓名时一定要精确匹配,不然就运行不出结果
String username =hashMap.get("username ");
String age =hashMap.get("age ");
String gender =hashMap.get("gender ");
String address =hashMap.get("address ");
String phone =hashMap.get("phone ");
user.setAddress(address).setAge(age).
setUsername(username).setGender(gender).setPhone(phone);
return user;
}
public static Student MyReflectMethod2(HashMap<String,String> hashMap){
Student student = new Student();
String username =hashMap.get("username");
String age =hashMap.get("age");
String gender =hashMap.get("gender");
String address =hashMap.get("address");
String phone =hashMap.get("phone");
student.setAddress(address).setAge(age).
setUsername(username).setGender(gender).setPhone(phone);
return student;
}*/
}
テストクラス
public class Reflect01Demo {
public static void main(String[] args) {
Map map = new HashMap<String,String>();
map.put("username","甄志丙");
map.put("age","18");
map.put("gender","男");
map.put("address","终南山");
map.put("phone","110");
Student student1 = MyReflectUtils.MyReflectMethod((HashMap<String, String>) map, Student.class);
System.out.println(student1);
User user1 = MyReflectUtils.MyReflectMethod((HashMap<String, String>) map, User.class);
System.out.println(user1);
}
}
試験結果
リフレクションの利点
上記のケースを考えてみてください。なぜリフレクションがフレームワークの魂なのですか?
1)リフレクションは、実行中のプロセス中にプログラムがターゲットオブジェクトを操作するための実行可能な方法を提供します。これにより、プログラムの柔軟性が大幅に向上します。
2)リフレクションメカニズムに基づいてプログラムのデカップリングが強化され、カップリングが減少し、プログラムのスケーラビリティが強化されます。
これまでのところ、リフレクションケースのレビューは完了しています。