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);
}
}