Java 反射(初步)

>反射要注意的點:

  • 反射入口,怎麼獲取類、方法、屬性對象
  • 其中方法中特殊的:通過反射的構造來獲取對象
  • 其中屬性中的應用:通過反射的屬性對象 獲取屬性名 拼接get/set方法名 進一步調用方法的應用

>獲取入口點Class<?> 的方式:

  • Class.forNme()
  • 類名.class
  • 對象引用.getClass()

>Reflection初步,以及解析一個類的信息

public class Re {
	/**
	 * 反射?(自己分析自己:通過自己的語法分析自己的類結構,並且能夠動態執行自己的類)
	 * 通過反射可以分析一個類的信息/結構 
	 * 可以執行一個類的方法  有些類沒有辦法new 比如在遠端,不在當前的class path下
	 * 
	 * spring ioc(工廠方法模式) aop(代理模式/bytecode instrument:插樁,修改字節碼文件;一個重要的庫:cglib主要完成插樁功能)
	 * 1.編譯時環境:Java代碼和編譯成class文件的階段;運行時環境:jvm運行編譯後的class文件的階段;
	 *   源碼-->編譯-->字節碼-->運行
	 *   在Java的運行環境中,對於任意一個類,可以通過反射,知道這個類有哪些屬性和方法;對於任意一個對象可以通過反射調用它的任意一個方法;
	 *   反射機制(reflection):動態獲取類的信息,動態調用對象的方法
	 * 
	 * 2.re主要功能:
	 *   在運行時判斷任意一個對象所屬的類
	 *   在運行時構造任意一個類的對象  (在編譯期,我們可以通過new寫在程序代碼裏)
	 *   在運行時判斷任意一個類所具有的成員變量和方法
	 *   在運行時調用任意一個對象的方法
	 * 
	 * 3.re概念:
	 *   Java動態語言性質(準動態語言):re機制允許程序在運行時透過Java提供的Reflection API取得任意一個  已知名稱  的類的內部信息
	 *   包括:其modifiers(如public static...)、superclass(如Object...)、實現之Interface(如Serializable)
	 *   也包括field成員變量和method方法的所有信息
	 *   並可以在運行時改變field的內容或者調用method方法
	 *   如:Spring中 bean的信息配置在 applicationContext.xml中,配置的類的名字都是字符串,Spring如何將字符串對應的類生成出來? 反射!
	 *   沒有反射,所有的框架都不存在。
	 *   
	 * 4.動態語言概念:
	 *   “程序運行時,允許改變程序結構或變量類型,這種語言稱爲動態語言” 如: var a="hello"; a=1;
	 *   從這個觀點看:Perl,Python,Ruby是動態語言 ;C++,Java,C#不是動態語言;
	 *   但是Java具有動態相關機制:Reflection。我們可以在  運行時  加載,探知,使用編譯期間完全未知的classes。
	 *   換句話說,Java程序可以加載一個運行時才得知名稱的class,獲悉完整的構造(不包括method定義:內部具體實現),並生成對象實體,或對其field設值,或喚起其method。
	 *   這種“看透class”的能力,稱爲introspection。
	 *   
	 * 5.Re API
	 *   JDK中,主要由以下類實現Java反射機制:
	 *   (主要位於java.lang.reflect包中)
	 *   --Class類:代表一個類
	 *   --Field類:代表類的成員變量
	 *   --Method類:代表類的方法
	 *   --Constructor類:代表類的構造方法
	 *   --Array類:提供動態創建數組,以及訪問數組的元素的靜態方法
	 * @throws ClassNotFoundException 
	 *   
	 */
	//從命令行接收一個字符串(該字符串是某個類的全名)
	//打印出該類中所有的所有的方法聲明
	public static void main(String[] args) throws ClassNotFoundException {
		//java.lang.Class java中每個對象都會有一個與之關聯的Class對象,Class對象是jdk啓動的時候就加載的,Class對象是唯一的;如生成了n個字符串對象,都會唯一的對應一個Class對象。
		//Class類是反射的入口點,Re必須從Class開始
		Class<?> classType=Class.forName(args[0]);//編譯時jdk並不知道這是什麼,運行時傳入
		
		//對於類中定義的任意一個方法,都會有一個與之關聯的Method對象,可以獲得除了方法體之外的內容
		Method[] methods = classType.getDeclaredMethods();
		
		for(Method method : methods){
			System.out.println(method);
		}
	}
}

>通過反射獲取一個類的實例和方法的調用

public class InvokeTester {

	public int add(int para1, int para2) {
		return para1 + para2;
	}

	public String echo(String msg) {
		return "hello" + msg;
	}
	
	public static void main(String[] args) throws Exception {
		//java內置的語法形式.class 會獲得InvokeTester類所對應的Class對象
		Class<?> classType = InvokeTester.class;
		//創建一個Class對象 所表示的類 的實例,newInstance使用條件:需要一個不帶參數的構造方法
		Object invokeTester = classType.newInstance();
		
		//以上兩行代碼等價於
		InvokeTester it = new InvokeTester();
		
		//獲取add()方法對應的Method對象(需要名字和參數;返回值並不屬於Java方法重載的範疇)  ...可變參數/相當於一個數組
		Method addMethod = classType.getMethod("add", new Class[]{int.class,int.class});
		//                               方法所在目標對象               參數
		Object result = addMethod.invoke(invokeTester, new Object[]{1,2});
		System.out.println((Integer)result);//3
		
		//以上兩行代碼等價於
		it.add(1, 2);
		
		Method echoMethod = classType.getMethod("echo", new Class[]{String.class});
	    result = echoMethod.invoke(invokeTester, "java");
	    System.out.println((String)result);//hellojava
	    
	    //以上兩行代碼等價於
	    it.echo("java");
	     
	}
}

>反射構造方式獲取一個類的實例、反射屬性進一步反射get/set方法

public class ReflectTester {

	public Object copy(Object object) throws Exception {
		Class<?> classType = object.getClass();

		System.out.println(classType.getName());

		// 通過構造方法生成類的實例 構造方法看參數區分
		Constructor<?> constructor = classType.getConstructor(new Class[] {});
		Object objectCopy = constructor.newInstance(new Object[] {});

		// 上面兩行代碼等價於(僅能用於不帶參構造)
		Object objectCopy2 = classType.newInstance();

		// 獲得對象所有的屬性
		Field[] fields = classType.getDeclaredFields();

		for (int i = 0; i < fields.length; ++i) {
			Field field = fields[i];

			String fieldName = field.getName();

			// 獲得屬性的首字母並轉換爲大寫 區間一般爲左閉右開
			String firstLetter = fieldName.substring(0, 1).toUpperCase();
			// 獲得屬性對應的getXXX() 名字
			String getMethodName = "get" + firstLetter + fieldName.substring(1);
			// 獲得屬性對應的setXXX() 名字
			String setMethodName = "set" + firstLetter + fieldName.substring(1);

			// 獲取get方法對應的method對象
			Method getMethod = classType.getMethod(getMethodName, new Class[] {});
			// 獲取set方法對應的method對象
			Method setMethod = classType.getMethod(setMethodName, new Class[] { field.getType() });

			Object value = getMethod.invoke(object, new Object[] {});

			System.out.println(fieldName + ":" + value);

			setMethod.invoke(objectCopy, new Object[] { value });
		}
		return objectCopy;
	}

	public static void main(String[] args) throws Exception {
		Customer customer = new Customer();
		customer.setId(new Long(1));
		customer.setName("zhangsan");
		customer.setAge(18);

		Customer customerCopy = (Customer) new ReflectTester().copy(customer);

		System.out.println(customerCopy.getId() + "," + customerCopy.getName() + "," + customerCopy.getAge());
	}
}

class Customer {

	private Long id;
	private String name;
	private int age;

	public Customer() {
		// TODO Auto-generated constructor stub
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章