新鮮出爐,深刻講解java反射的底層原理,這篇算講的不錯了!

反射

  1. 反射

Java代碼和Java文件

Java代碼基本格式
	1. Java代碼都在類內或者接口內
	2. 
		class 類名 {
			成員變量
			構造方法
			成員方法
			Annotation 註解
		}

Java文件要求:
	1. 一般狀況下一個Java文件對應一個Java類
	2. Java文件包含當前Java代碼的全部內容!!!

Java文件和.class字節碼文件

Java文件
	FirstJava.java
	經過編譯器 javac ==> javac FirstJava.java ==> FirstJava.class

.class字節碼文件是什麼???
	二進制可執行文件。
	.class字節碼文件中會包含Java文件的全部內容。
	.class字節碼文件包含Java程序的全部可執行內容(註釋不參與編譯和執行)。

class字節碼文件在內存中的位置

class字節碼文件和Java代碼關係

Class類相關方法

Class Class.forName(String packageNameAndClassName) throws ClassNotFoundException;
	根據完整的包名.類名獲取對應的Class類對象
	ClassNotFoundException 未找到指定類

Class 類對象.getClass();
	經過類對象獲取當前類對象對應的Class類對象
	例如:
		Person p = new Person();  p.getClass() ==> Person類對應Class對象

Class 類名.class;
	經過類名獲取當前類對應屬性 Class對象
	例如: 
		Person.class ==> Person類對應Class對象。
package com.qfedu.a_reflect;

/**
 * Class類方法演示
 * 
 * @author 期年以前ying@
 *
 */
public class GetClassObject {
	public static void main(String[] args) throws ClassNotFoundException {
		/*
		 * Class Class.forName(String packageNameAndClassName) 
		 * 			throws ClassNotFoundException;
		 */
		Class cls1 = Class.forName("com.project.a_reflect.Person");
		
		/*
		 * Class 類對象.getClass();
		 */
		Person person = new Person();
		Class cls2 = person.getClass();
		
		/*
		 * Class 類名.class;
		 */
		Class cls3 = Person.class;
		
		/*
		 
		 * 		無論是經過哪種方式獲取指定類的Class對象,都是同一個Class對象
		 * 由於當前Person類在當前程序中有且只佔用一次代碼區空間。
		 */
		System.out.println("cls1 == cls2 : " + (cls1 == cls2));
		System.out.println("cls2 == cls3 : " + (cls2 == cls3));
		System.out.println("cls3 == cls1 : " + (cls3 == cls1));
	}
}

操做Constructor 構造方法類

經過Class類對象獲取對應類的Constructor構造方法類對象

Constructor[] getConstructors();
	獲取當前Class對象對應類中全部非私有化構造方法類對象數組。
	
Constructor[] getDeclaredConstructors();
	【暴力反射】
	獲取當前Class對象對應類中的全部構造方法類對象數組,包括私有化構造方法。
	
Constructor getConstructor(Class... parameterTypes);
	獲取當前Class對象中,指定參數數據類型的構造方法。獲取的構造方法爲非私有化構造方法
	Class... parameterTypes 
		Class類型不定長參數,用於約束當前構造方法對應的數據類型。
	例如:
		無參數構造方法
		cls.getConstructor(); ==> Person();
		兩個參數構造方法(int, String)
		cls.getConstructor(int.class, String.class) ==> Person(int, String)
		
Constructor getDeclaredConstructor(Class... parameterTypes);
	【暴力反射】
	獲取當前Class對象中,指定數據類型的構造方法,包括私有化構造方法
	例如:
		獲取私有化String類型構造方法
		cls.getDeclaredConstructor(String.class) ==> private Person(String.class)

操做Constructor類對象建立對應類對象

Object newInstance(Object... parameters);
	經過Constructor類對象,執行對應的構造方法,建立對應類對象
	Object... 不定長參數,要求數據類型爲Object類型。
	例如:
		Person(); 無參數構造方法
		Person p1 = (Person) constructor.newInstance();
		Person(int, java.lang.String);
		Person p2 = (Person) constructor.newInstance(10, "Java真好學");
package com.qfedu.a_reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 操做Constructor構造方法類對象
 * 
 * @author 期年以前ying@
 *
 */
public class GetConstructorObject {
	public static void main(String[] args) 
			throws ClassNotFoundException, NoSuchMethodException, SecurityException, 
			InstantiationException, IllegalAccessException, IllegalArgumentException, 
			InvocationTargetException {
		/*
		 * Class Class.forName(String packageNameAndClassName) 
		 * 			throws ClassNotFoundException;
		 */
		Class cls = Class.forName("com.project.a_reflect.Person");
		
		/*
		 * 1. 獲取當前Class對象對應類中全部非私有化構造方法類對象數組
		 */
		Constructor[] constructors = cls.getConstructors();
		for (Constructor constructor : constructors) {
			System.out.println(constructor);
		}
		
		System.out.println();
		
		/*
		 * 2. 【暴力反射】
		 * 獲取當前Class對象對應類中的全部構造方法類對象數組,包括私有化構造方法。
		 */
		Constructor[] declaredConstructors = cls.getDeclaredConstructors();
		for (Constructor constructor : declaredConstructors) {
			System.out.println(constructor);
		}
		
		System.out.println();
		
		/*
		 * 3. 獲取當前Class對象中,指定參數數據類型的構造方法。獲取的構造方法爲非私有化構造方法
		 */
		Constructor constructor1 = cls.getConstructor();
		Constructor constructor2 = cls.getConstructor(int.class);
		Constructor constructor3 = cls.getConstructor(int.class, String.class);
		System.out.println(constructor1);
		System.out.println(constructor2);
		System.out.println(constructor3);
		
		/*
		 * 4. 【暴力反射】	
		 *	獲取當前Class對象中,指定數據類型的構造方法,包括私有化構造方法
		 */
		Constructor constructor4 = cls.getDeclaredConstructor(String.class);
		System.out.println(constructor4);
		
		System.out.println();
		/*
		 * newInstance 建立類對象
		 */
		Person p1 = (Person) constructor1.newInstance();
		Person p2 = (Person) constructor2.newInstance(10);
		Person p3 = (Person) constructor3.newInstance(20, "張三愛Java");
		System.out.println(p1);
		System.out.println(p2);
		System.out.println(p3);
		
		/*
		 * 給予暴力反射操做使用權限!!!
		 * setAccessible(boolean flag);
		 */
		constructor4.setAccessible(true);
		Person p4 = (Person) constructor4.newInstance("Java快樂多");
		System.out.println(p4);
	}
}

操做 Method 成員方法類

經過Class類對象獲取對應類的Method成員方法類對象

Method[] getMethods();
	經過Class類對象調用,獲取當前類內的全部非私有化成員方法,包含從父類繼承而來子類可使用的非私有化方法。
	
Method[] getDeclaredMethods();
	【暴力反射】
	經過Class類對象調用,獲取當前類內的全部成員方法,包括私有化成員方法,可是不包括從父類繼承而來的方法。
	
Method getMethod(String methodName, Class... parameterTypes);
	經過Class類對象調用,根據方法名稱和對應的形式參數列表數據類型獲取對應的成員方法,能夠獲取父類繼承方法,不能獲取私有化成員方法
	例如:
		無參數成員方法 獲取 game();
			cls.getMethod("game");
        有參數成員方法 獲取 game(String);
            cls.getMethod("game", String.class);
	
Method getDeclaredMethod(String methodName, Class... parameterTypes);
	經過Class類對象調用,根據方法名稱和對應的形式參數列表數據類型獲取對應的成員方法,能夠獲取私有化成員方法,不能獲取父類成員方法。
	例如:
		無參數私有化成員方法 testPrivate();
			cls.getDeclaredMethod("testPrivate");
		有參數私有化成員方法 testPrivate(String);
			cls.getDeclaredMethod("testPrivate", String.class);

操做Method類對象執行方法

Object invoke(Object obj, Object... parameters);
	經過Method類對象調用,執行對應方法。
	Object obj 執行當前方法的類對象。
	Object... parameters 對應當前方法的實際參數列表
package com.qfedu.a_reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 操做Method類對象
 * 
 * @author 期年以前ying@
 *
 */
public class GetMethodObject {
	public static void main(String[] args) 
			throws ClassNotFoundException, SecurityException, NoSuchMethodException, 
			InstantiationException, IllegalAccessException, IllegalArgumentException, 
			InvocationTargetException {
		/*
		 * Class Class.forName(String packageNameAndClassName) 
		 * 			throws ClassNotFoundException;
		 */
		Class cls = Class.forName("com.project.a_reflect.Person");
		
		/*
		 * 1. 經過Class類對象調用,獲取當前類內的全部非私有化成員方法,
		 * 包含從父類繼承而來子類可使用的非私有化方法。
		 */
		Method[] methods = cls.getMethods();
		for (Method method : methods) {
			System.out.println(method);
		}
		
		System.out.println();

		/*
		 * 2. 獲取當前類自有成員方法,包括私有化方法,可是不包含父類繼承給子類的方法
		 */
		Method[] declaredMethods = cls.getDeclaredMethods();
		for (Method method : declaredMethods) {
			System.out.println(method);
		}
		System.out.println();
		
		/*
		 *  3. 根據指定方法名字和參數類型,獲取非私有化成員方法
		 */
		Method game1 = cls.getMethod("game");
		Method game2 = cls.getMethod("game", String.class);
		
		System.out.println(game1);
		System.out.println(game2);
		System.out.println();
		
		/*
		 * 4. 根據指定的方法名稱和參數類型,獲取私有化成員方法
		 */
		Method testPrivate1 = cls.getDeclaredMethod("testPrivate");
		Method testPrivate2 = cls.getDeclaredMethod("testPrivate", String.class);
		System.out.println(testPrivate1);
		System.out.println(testPrivate2);
		System.out.println();
		
		/*
		 * 調用方法
		 */
		Object object = cls.getConstructor().newInstance();
		game1.invoke(object);
		game2.invoke(object, "World Of Tank");
		
		/*
		 * 給予暴力反射操做權限
		 */
		testPrivate1.setAccessible(true);
		testPrivate2.setAccessible(true);
		testPrivate1.invoke(object);
		testPrivate2.invoke(object, "西紅柿+黃瓜+雞蛋+羊肉串");
	}
}

操做 Field 成員變量類

經過Class類對象獲取對應類的Field成員變量類對象

Field[] getFields();
	獲取類內全部非私有化成員變量數組
	
Field[] getDeclaredFields();
	【暴力反射】
	獲取類內全部成員變量數組,包括私有化成員變量
Field getField(String fieldName);
	根據成員變量名字獲取對應的成員變量對象,要求當前成員變量非私有化
	例如:	
		public int test;
		cls.getField("test");

Field getDeclaredField(String fieldName);
	【暴力反射】
	獲取類內指定名字的成員變量對象,包括私有化成員變量
	例如:
		private String name;
		private int id;
		cls.getDeclaredField("name");
		cls.getDeclaredField("id");

操做Field類對象賦值取值成員變量

Field[] getFields();
	獲取類內全部非私有化成員變量數組
	
Field[] getDeclaredFields();
	【暴力反射】
	獲取類內全部成員變量數組,包括私有化成員變量
Field getField(String fieldName);
	根據成員變量名字獲取對應的成員變量對象,要求當前成員變量非私有化
	例如:	
		public int test;
		cls.getField("test");

Field getDeclaredField(String fieldName);
	【暴力反射】
	獲取類內指定名字的成員變量對象,包括私有化成員變量
	例如:
		private String name;
		private int id;
		cls.getDeclaredField("name");
		cls.getDeclaredField("id");
package com.qfedu.a_reflect;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * 操做Field類對象
 * 
 * @author 期年以前ying@
 *
 */
public class GetFieldObject {
	public static void main(String[] args) 
			throws ClassNotFoundException, NoSuchFieldException, SecurityException,
			InstantiationException, IllegalAccessException, IllegalArgumentException, 
			InvocationTargetException, NoSuchMethodException {
		/*
		 * Class Class.forName(String packageNameAndClassName) 
		 * 			throws ClassNotFoundException;
		 */
		Class cls = Class.forName("com.project.a_reflect.Person");
		
		/*
		 * 1. 獲取類內全部非私有化成員變量數組
		 */
		Field[] fields = cls.getFields();
		for (Field field : fields) {
			System.out.println(field);
		}
		System.out.println();
		
		/*
		 * 2. 獲取類內全部成員變量數組,包括私有化成員變量
		 */
		Field[] declaredFields = cls.getDeclaredFields();
		for (Field field : declaredFields) {
			System.out.println(field);
		}
		System.out.println();
		
		/*
		 * 3. 根據成員變量名字獲取對應的成員變量對象,要求當前成員變量非私有化
		 */
		Field test = cls.getField("test");
		System.out.println(test);
		System.out.println();
		
		/*
		 * 4. 獲取類內指定名字的成員變量對象,包括私有化成員變量
		 */
		Field id = cls.getDeclaredField("id");
		Field name = cls.getDeclaredField("name");
		System.out.println(id);
		System.out.println(name);	
		System.out.println();
		
		/*
		 * 取值賦值成員變量
		 */
		Object obj = cls.getConstructor().newInstance();
		System.out.println(obj);
		test.set(obj, 100);
		System.out.println(obj);
		System.out.println(test.get(obj));
		
		id.setAccessible(true);
		name.setAccessible(true);
		
		id.set(obj, 10);
		name.set(obj, "大哥好威武");
		System.out.println(obj);
		System.out.println(id.get(obj));
		System.out.println(name.get(obj));
		
		System.out.println();
		System.out.println(id.getType());
		System.out.println(name.getType());
	}
}

暴力反射受權

class AccessibleObject 類內方法
public static void setAccessible(AccessibleObject[] array, boolean flag);
	經過類名調用的靜態工具方式,給予AccessibleObject類對象或者其子類對象數組,賦值操做權限。
	子類對象包括: Field Method Constructor
	
public void setAccessible(boolean flag);
	經過AccessibleObject類對象調用,單一權限受權,Field Method Constructor均可以使用。

案例操做

須要使用
	1. String方法
	2. IO流 推薦字符流操做
	3. 反射
	4. 自行了解 ==> String 轉其餘類型方法 百度 parse系列方法
文件名:
	studentInfo.txt
文件內容:
className=com.qfedu.a_reflect.Student
name=李四
age=18
gender=false
javaScore=59
webScore=59
dbScore=59

目標
	文件內容轉Student類對象
package com.qfedu.a_reflect;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;

@SuppressWarnings("all")
public class ReflectDemo {
	public static void main(String[] args) 
			throws IOException, ClassNotFoundException, InstantiationException, 
			IllegalAccessException, IllegalArgumentException, InvocationTargetException,
			NoSuchMethodException, SecurityException, NoSuchFieldException {
		// 1. 建立緩衝字符輸入流 處理 文件
		BufferedReader br = new BufferedReader(new FileReader("./data/studentInfo.txt"));
		
		// 2. 讀取文件數據
		String classInfo = br.readLine();
		String className = classInfo.substring(classInfo.indexOf("=") + 1);
		
		// 3. 啓動萬惡之源 獲取Class對象,加載指定類
		Class cls = Class.forName(className);
		
		// 4. 建立對應類對象
		Object obj = cls.getConstructor().newInstance();
		
		// 5. 讀取文件,利用循環操做
		String info = null;
		Object value = null;
		
		// 每一次從文件中讀取一行數據
		while ((info = br.readLine()) != null) {
			// 按照 = 分割信息 name=李四
			String[] split = info.split("=");
			System.out.println(Arrays.toString(split));
			// 根據信息獲取對應成員變量對象
			Field field = cls.getDeclaredField(split[0]);
			field.setAccessible(true);
			
			// 獲取成員變量數據類型
			Class type = field.getType();
			
			// 當前成員變量數據爲String類型
			if (type.equals(String.class)) {
				value = split[1];
				// field.set(obj, split[1]);
			// 成員變量數據類型爲int類型
			} else if (type.equals(int.class)) {
				value = Integer.parseInt(split[1]);
			// 成員變量數據類型爲boolean類型
			} else if (type.equals(boolean.class)) {
				value = Boolean.parseBoolean(split[1]);
			}
			
			field.set(obj, value);
		}
		
		System.out.println(obj);
		
		// 關閉資源
		br.close(); 
	}
}

最後

歡迎關注公衆號:前程有光,領取一線大廠Java面試題總結+各知識點學習思惟導+一份300頁pdf文檔的Java核心知識點總結! 這些資料的內容都是面試時面試官必問的知識點,篇章包括了不少知識點,其中包括了有基礎知識、Java集合、JVM、多線程併發、spring原理、微服務、Netty 與RPC 、Kafka、日記、設計模式、Java算法、數據庫、Zookeeper、分佈式緩存、數據結構等等。java

相關文章
相關標籤/搜索