1. 程式人生 > >Java 反射機制 的超簡單例項分析

Java 反射機制 的超簡單例項分析

  菜鳥 第一次寫這啥部落格 呵呵  就前幾天面試  面試官提到的Java反射機制 沒有回答上來 回來鑽研了一下 只是一些很淺顯的東西 菜鳥而已(高手們懂的) 廢話不多說 言歸正傳

一   什麼是 Java反射機制  有什麼用

         (1): JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。

      (2):Java的反射機制它知道類的基本結構,這種對Java類結構探知的能力,我們稱為Java類的“自審”。

              (可以進行百度或google 有詳細的解釋 嘻嘻 偷點懶)

二   Java反射機制主要提供了以下功能

                             在執行時判斷任意一個物件所屬的類;在執行時構造任意一個類的物件;在執行時判斷任意一個類所具有的成員變數和方法;在執行時呼叫任意一個物件的方法;生成動態代理。

    用例項 來說明

         (1) class 類的使用:獲取類的屬性、方法、構造方法、類的相關資訊

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
 * 
 * @author lijian
 *class 類的使用:獲取類的屬性、方法、構造方法、類的相關資訊
 */
public class TestClass_1 {

	public static void main(String[] args) throws ClassNotFoundException {
       //forName(String className)返回與帶有給定字串名的類或介面相關聯的 Class 物件。
		Class clazz = Class.forName("java.lang.String");
	   //getDeclaredFields();返回 Field 物件的一個數組,這些物件反映此 Class 物件所表示的類或介面所宣告的所有欄位,包括公共、保護、預設(包)訪問和私有欄位,但不包括繼承的欄位。
		Field[] field = clazz.getDeclaredFields();
		System.out.println("---------------------顯示類的屬性----------------------------");
		for (Field f : field) {
			//getName()返回此 Field 物件表示的欄位的名稱
			//getType()返回一個 Class 物件,它標識了此 Field 物件所表示欄位的宣告型別。
			System.out.println(f.getName() + "        " + f.getType());
		}
		System.out.println("---------------------顯示類的方法-----------------------------");
		//getDeclaredMethods() 返回一個 Method 物件,該物件反映此 Class 物件所表示的類或介面的指定已宣告方法。
		Method[] method = clazz.getDeclaredMethods();
		for (Method m : method) {
			System.out.println(m.getName());
		}
		System.out.println("---------------------顯示類的構造方法-----------------------------");
		//getDeclaredConstructors() 返回 Constructor 物件的一個數組,這些物件反映此 Class 物件表示的類宣告的所有構造方法。
       Constructor[] constructors = clazz.getDeclaredConstructors();
       for(Constructor c:constructors)
       {
    	   System.out.println(c);
       }
 	  System.out.println("----------------------獲取類的相關的資訊----------------------------------------------");
 	  System.out.println("類所在的包為:"+ clazz.getPackage().getName());
 	  System.out.println("類名:"+ clazz.getName());
 	  System.out.println("父類的名稱:"+ clazz.getSuperclass().getName());
 	  
	}
}

    (可以執行瞧瞧效果····嘿嘿)

    以下示例中會使用到User.java類,其程式碼如下:

      
public class User {

	private String name;
	private int age;
   
	public User(){}
	public User(String name, int age) {
	}
屬性的setter 和getter 方法 省略······

     (2)生成一個類的Class物件有一下四種方式

import entity.User;

/**
 * 
 * @author lijian 
 * 建立Class物件的4種方法
 */
public class TestClass_2 {

	public static void main(String[] args) throws ClassNotFoundException {
		User user = new User();
		// 第一種:物件.Class
		Class clazz = user.getClass();
		// 使用包裝器獲取Class 物件
		String str = "asdasd";
		clazz = str.getClass();
		// 第二種 :類.class
		clazz = User.class;
		clazz = String.class;
		clazz = Integer.class;

		// 第三種:Class.forname();
		clazz = Class.forName("java.lang.String");
		clazz = Class.forName("java.lang.Long");
       
		//第四種:包裝類.type
		clazz = Integer.TYPE;
	}
}

      (3)使用反射動態建立物件例項     有兩種方式:

                      方法一:通過Class的newInstance()方法

                                       該方法要求該Class 物件的對應類有無參構造方法

                                        執行newInstance()實際上就是執行無參構造方法來建立該類的例項

                      方法二:通過Constructor的newInstance() 方法

                                         先使用Class物件獲得指定的Constructor物件

                                          再呼叫Constructor物件的newInstance()方法來建立該Class物件對應類的物件

                                           通過該方法可以選擇使用指定的構造方法來建立物件

             下面就兩種方法寫個簡單的例項

import java.lang.reflect.Constructor;
import entity.User;

/**
 * 
 * @author lijian
 *  使用反射 動態建立物件  兩種方式
 */
public class TestClass_3 {
	public static void main(String[] args) throws Exception {
		/**
		 * 方法1:通過Class的newInstance()方法
		 *          該方法要求該Class物件的對應類有無參構造方法
		 *              執行newInstance()實際上就是執行無參構造方法來建立該類的例項
		 */
	//      Class  clazz = Class.forName("entity.User");
	//	Object obj =  clazz.newInstance();
		
		/**
		 * 方法2:通過Constructor的newInstance()方法
		 *             先使用Class物件獲取指定的Constructor物件
		 *             再呼叫Constructor物件的newInstance()方法來建立該Class物件對應類的物件
		 *              通過該方法可選擇使用指定構造方法來建立物件
		 */
		Class clazz = Class.forName("entity.User");
		//指定有參的構造方法
		Constructor cons = clazz.getConstructor(new Class[] {int.class,String.class,String.class});
		//使用有引數的構造方法例項物件
                Object obj = cons.newInstance(new Object[]{1,"scott","1234"});
                //轉換為實際操作類
                User user = (User)obj;

                //也可以呼叫無參構造方法,比第一種方法複雜
                obj = clazz.getConstructor(new Class[]{}).newInstance(new Object[]{});
                user = (User)obj;
                //以下也可以呼叫無參構造方法
                obj = clazz.getConstructor().newInstance();
                //轉換為實際操作類
                 user = (User)obj;
	}

}

     (4)使用反射動態修改查詢的屬性值

              通過Class物件的getFields() 或者getField()方法可以獲得該類所包括的全部Field屬性或指定Filed屬性。Field類提供了以下方法來方法訪問屬性

                    getXxx(Object   obj) :獲取obj物件該Field的屬性值。此處的Xxx對應8個基本資料型別,如果該屬性型別是引用型別則直接使用get(Objectobj)

                    setXxx(Object obj,Xxx val) :將obj物件的該Field賦值val。此處的Xxx對應8個基本資料型別,如果該屬性型別是引用型別則直接使用set(Objectobj, Object val)

                    setAccessible(Boolean flag):若flag為true,則取消屬性的訪問許可權控制,即使private屬性也可以進行訪問

import java.lang.reflect.Field;


/**
 * 
 * @author lijian
 *    使用反射動態修改查詢屬性值
 */
public class TestClass_4 {

	public static void main(String[] args) throws Exception {
		Class clazz = Class.forName("entity.User");
		Object obj = clazz.newInstance();//獲得類的例項
		//獲得 User 類中的指定屬性對應的Field物件(每個屬性對應一個Field物件)
		Field field = clazz.getDeclaredField("name");
		
		//取消屬性的訪問許可權控制,即使private 屬性也可以進行訪問
		field.setAccessible(true);
		//呼叫 getter 方法獲取屬性值
		System.out.println(field.get(obj));
		//呼叫setter 方法給屬性賦值
		field.set(obj, "scott");
		//呼叫 getter 方法獲取對應屬性修改後的值
		System.out.println(field.get(obj));
	}
}


       (5)使用反射動態執行方法

                            通過Class物件的getMethods()方法可以獲得該類所包括的全部方法,返回值是Method[]

                            通過Class物件的getMethod() 方法可以獲得該類所包括的執行方法,返回值是Method

                                   每個Method物件對應一個方法,獲得Method物件後,可以呼叫其invoke()     來呼叫對應方法                                

                                       Objectinvoke(Object obj , Object [] args):   obj代表當前方法所屬的物件的名字,

                                                                                                                   args代表當前方法的引數列表,

                                                                                                                    返回值Object是當前方法的返回值,即執行當前方法的結果。

import java.lang.reflect.Method;
import entity.User;

/**
 * 
 * @author lijian
 *  使用反射動態執行方法
 */
public class TestClass_5 {

	public static void main(String[] args) throws Exception{
		
		Class clazz = User.class;
		Object obj = clazz.newInstance();
		
		
		//呼叫該物件的 setName方法
		Method method = clazz.getMethod("setName", new Class[]{String.class});
		Object result =method.invoke(obj, new Object[]{"scott"});       //  obj.setName("scott");
		System.out.println("返回值為:"+result);
		
		//呼叫物件的getName()方法
		Method method1 = clazz.getMethod("getName", new Class[]{});
		Object obj1 = method1.invoke(obj, new Object[]{});
		System.out.println("返回值為:"+obj1);
	}
}


(6)使用反射動態建立陣列並存取元素

                         在java.lang.reflect包下提供了Array類,包括一系列static方法,通過這些方法可動態的建立陣列、給元素賦值、取出元素值等

                         Array提供的主要方法如下:

                             static ObjectnewInstance(Class<?> componentType, int[] dim) :建立一個具有指定的元件型別和維度的新陣列

                             static void setXxx(Objectarray, int index ,xxx val):給陣列物件array中第index個元素賦值val

                              static xxx getXxx(Objectarray, int index):以 xxx形式返回指定陣列物件array中第index個元素值

                      <1>動態建立一維陣列,並給陣列賦值:                   
import java.lang.reflect.Array;

/**
 * 
 * @author lijian
 *  動態建立一維陣列,並給陣列賦值:
 */
public class TestClass_6 {

    public static void main(String[] args) throws Exception  {   
          Class clazz = Class.forName("java.lang.Integer");
          Object array = Array.newInstance(clazz, 10);//根據類的class 建立大小為10的陣列
          Array.set(array, 5, 10);//給陣列的第5個元素賦值為10
          Object el = Array.get(array, 5);//取出陣列的第5個元素值顯示
          System.out.println(el);
	}

}

                    <2>動態建立二維陣列,並給陣列賦值:
import java.lang.reflect.Array;

/**
 * 
 * @author lijian
 *動態建立二維陣列,並給陣列賦值:
 */
public class TestClass_7 {

	public static void main(String[] args) {
		int dims[] = {10,15};
		Object  array = Array.newInstance(int.class, dims);//建立一個10行15列二維陣列,等價與:array[10][15]
		Object  array1 = Array.get(array, 5);//獲取二維陣列中的第5行
		Array.set(array1, 8, 300);     //給陣列的第5行8列賦值300,等價與:array[5][8]=300
		Object el = Array.get(array1, 8);//取出陣列中第5行8列的值
		System.out.println(el);
	}
}