Java反射機制 前言 更多文章請一步本人博客 "https://chenjiabing666.github.io/" "網頁版的jdk的API" "離線版API" 什麼是反射機制 反射是java語言的一個特性,它允程式在運行時(註意不是編譯的時候)來進行自我檢查並且對內部的成員進行操作。例如它允許 ...
Java反射機制
前言
- 更多文章請一步本人博客https://chenjiabing666.github.io/
- 網頁版的jdk的API
- 離線版API
什麼是反射機制
反射是java語言的一個特性,它允程式在運行時(註意不是編譯的時候)來進行自我檢查並且對內部的成員進行操作。例如它允許一個java的類獲取他所有的成員變數和方法並且顯示出來。這個能特定我們不常看到,但是在其他的比如C或者C++語言中很不就存在這個特性。一個常見的例子是在JavaBean中,一些組件可以通過一個構造器來操作。這個構造器就是用的反射在動態載入的時候來獲取的java中類的屬性的。
主要的類
Class
類的實例表示正在運行的 Java 應用程式中的類和介面。Class沒有公共的構造方法,Class 對象是在載入類時由 Java 虛擬機以及通過調用類載入器中的 defineClass 方法自動構造的Constructor
提供關於類的單個構造方法的信息以及對它的訪問許可權(主要提供的是對構造方法使用)Method
提供關於類或介面上單獨某個方法(以及如何訪問該方法)的信息。所反映的方法可能是類方法或實例方法(包括抽象方法)Field
主要提供對類中的成員變數的訪問和使用
Class
Class類也使用了泛型,即是Class
這種形式的,可以直接使用一個具體的類傳入,這樣的話就不需要強制轉換了,比如 Class.newInstance()
這樣使用預設的構造方法構造一個對象就需要不再需要強制轉換了即使用(ClassName)Class.newInstance()
常用的方法
getConstructor(Class[] params)
獲取公共的(public)的構造方法,並且限定其中的參數個數和類型可以獲得不同的公共構造方法Constructor[] getConstructors()
返回所有的公共(public)的構造方法getDeclaredConstructor(Class[] params)
獲取所有指定的構造方法,但是需要註意的是當獲取私有的構造方法的時候需要使用setAccessible設置訪問許可權為true才能進行構造,否則出現異常Constructor[] getDeclaredConstructors()
返所有的構造方法包括public和private,protected修飾的T newInstance()
返回的是一個調用預設的構造方法(public class_name())實例化的一個Object對象,如果使用泛型那麼就返回T類型的,反之返回的是Object需要強制轉換才能使用這個對象調用成員函數和成員變數Class forName(String class_name)
返回class對象,每一個對都有一個方象法返回Class對象(test.class)Package getPackage()
返回此類所在的包名(package demo) 當然也可以使用Package.getName()獲得包的名字(demo)比如constructor.getPackage().getName()
int getModifiers()
返回的是類的修飾符的整數 類型(修飾符的類型有public private protected)其中得到整數可以使用Modifier中toString(int num)得到public,private,protected的類型,比如Modifier.toString(class1.getModifiers())
*Method getMethod(String name, Class<?>... parameterTypes)
返回指定參數的方法Method對象,註意這裡僅僅是返回的時公共的方法(public) 比如:Method method=class1.getMethod("display",new Class[]{int.class})
這裡的display
是方法的名字,有一個參數,類型為intMethod[] getMethods()
獲取所有的公共的方法(public)返回的是一個數組(Method)Method getDeclaredMethod(String name,Class<?>... parameterTypes)
返回所有的指定的參數的方法(public,private,protected,但是不包括繼承的),其中參數可以為null(無參數)Method[] getDeclaredMethods()
獲取所有的方法Field getField(String name)
指定名字的公共成員變數(public)Field[] getFields()
獲取所有的公共的成員變數Field getDeclaredField(String name)
獲取所有的指定名稱的成員變數(public,protected,private),同樣在調用私有成員變數的時候需要先設置訪問的許可權,field.setAccessible(true)Field[] getDeclaredFields()
獲取所有的成員變數(public,protected,private)getSuperclass()
返回表示此 Class 所表示的實體(類、介面、基本類型或 void)的超類的 Class。URL getResource(String name)
查找指定名稱的資源(圖片,文件...)註意這個資源一定要和指定類在一個包中,否則返回null,比如查找Test類下的airplane.png圖片:Test.class.getResource("airplane.png")
這裡返回的將是絕對路徑
獲取Class的對象並且實例化
- 使用
Class.forName(String className)
其中className一定是包含包的名字,下麵的demo就是包的名字,Test是類的名字。這是最常用的方法,學過JDBC的都知道載入驅動的時候就是使用的Class.forName()
/*
* 第一種使用forName(String className),其中className一定是包含包的名字,下麵的demo就是包的名字,Test是類的名字
*/
Class cls=Class.forName("demo.Test");
Test test=(Test)cls.newInstance(); //這裡只是使用了預設的構造方法實例化對象
- 使用
類名.class
Class cls=Test.class;
- 使用
對象.getClass()
Test test=new Test();
Class cls=test.getClass();
Constructor
- 主要是用來對類的構造方法進行操作的,可以看出這個也使用了泛型,和上面的Class是一樣的,註意這裡如果沒有使用泛型,那麼原本放回
T
類型的現在都是返回Object
常用的方法
T newInstance(Object parms)
使用帶有參數的構造方法實例化對象,如果使用了泛型,那麼返回的就是T類型的,反之返回的是Object類型的,需要強制轉換getName()
以字元串的形式返回構造方法的名稱,具體的路徑包含包名(demo.Test)int getModifiers()
和Class
類中的方法一樣
Method
主要提供的是對類中的方法的操作
常用的方法
Object invoke(Object obj,object args)
使用得到的Method
對象調用方法,obj
是類的已經構造好的對象,如果是靜態方法直接寫null,因為靜態方法的調用不需要對象,返回值是Object類型的,如果接受返回值,需要使用強制轉換成相應的類型,args
是傳入的參數,如果有多個參數,那麼可以直接在後面用逗號添加或者直接創建數組new Object[]{22,"chenjiabing"}
比如:method.invoke(test,22,"chenjiabing")
method.invoke(test,new Object[]{22,"chenjiabing"})
註意:如果調用的private類型的方法,那麼需要在前面設置訪問的許可權,method.setAccessible(true)
String getName()
返回此方法的名字(display)Modifier getModifiers()
返回此方法的修飾符的類型表示的整數(public,private...),可以使用Modifier.toString()
轉換成字元串形式Class getReturnType()
返回這個方法的返回類型String toString()
返回這個方法表示的字元串的形式
Field
主要提供對類的成員變數的操作
常用方法
String getName()
返回變數名字Object get(Object obj)
返回此變數在指定對象中的值,因為在構造對象的時候每一個傳入的變數的值都不一樣,因此需要使用對象obj。obj表示傳入的對象,返回的Object類型,因此需要強制轉換void set(Object obj,Object value)
改變obj對象上的變數的值為valueModifier getModifiers()
返回整數表示修飾的類型String getType()
獲取變數的類型(int,String,double float.....)
Modifier
Modifier 類提供了 static 方法和常量,對類和成員訪問修飾符進行解碼。修飾符集被表示為整數,用不同的位位置 (bit position) 表示不同的修飾符。
常用的方法
static String toString(int mode)
將代表修飾符的整數形式轉換為字元串形式的修飾符,比如將1轉換成publicstatic isInterface(int mode)
如果整數參數包括 interface 修飾符,則返回 true,否則返回 falsestatic isStatic(int mode)
static isPrivate(int mode)
static isPublic(int mode)
static isAbstract(int mode)
實例
Modifier.toString(Test.class.getModifiers()) //得到Test類的修飾符
使用
有了上面的鋪墊,我們就可以使用上面的這些類進行操作了,在進行操作之前,我們需要先定義一個類
Test
,放在demo
包下,內容如下
package demo;
import java.util.jar.Attributes.Name;
import javax.print.attribute.standard.MediaSize.NA;
public class Test {
public String name;
private int age;
public Test() {
this.name = "陳加兵";
this.age = 23;
}
public Test(String name, int age) {
this.name = name;
this.age = age;
}
public void display() {
System.out.println("name=" + this.name + "----age=" + this.age);
}
public void set(String name, int age) {
this.name = name;
this.age = age;
}
private int getAge() {
return this.age;
}
}
實例化對象
- 使用Class預設的構造newInstance()
Class class1=Class.forName("demo.Test"); //靜態載入Class
Test test=(Test)class1.newInstance(); //調用預設的構造方法(public Test())實例化對象,由於沒有使用泛型,因此需要強轉
test.display(); //調用display方法
- 使用Class中的
getConstructor()
方法構造對象,需要註意的使用private
類型構造方法時一定要先設置訪問許可權為true
-constructor.setAccessible(true)
;
/*
*調用public Test(String name,int age)得到Constructor的兩種形式
* 1.Constructor constructor=class1.getConstructor(new Class[]{String.class,int.class});
* 2.Constructor constructor=class1.getConstructor(String.class,int.class);這個和上面的是一樣的,就是使用的參數形式不一樣
*
*
*
*
*使用newInstance()構造對象的兩種方式
* 1.Test test=(Test)constructor.newInstance(new Object[]{"chenjiabing",22});
* 2.Test test=(Test)constructor.newInstance("chenjiabing",22); 只是形式不同而已,不過我還是喜歡上面的形式
*
*/
/*
* 調用public Test(String name,int age)
* Class.getConstructor()得到的是公共的構造方法,如果有私有的構造方法,那麼就會報錯,這時就要使用getDeclaredConstructor(Class<?>... parameterTypes)
* Test test=(Test)constructor.newInstance("陳加兵",22);
*
*
* 調用public Test()
* Constructor constructor=class1.getConstructor(null);
* Test test=(Test)constructor.newInstance(null);
*
*
* 調用private Test(int age)
* Constructor constructor=class1.getDeclaredConstructor(new Class[]{int.class});
constructor.setAccessible(true); //因為private類型是不可以直接訪問的,因此需要設置訪問許可權為true
Test test=(Test)constructor.newInstance(new Object[]{1000});
*/
Class class1=Class.forName("demo.Test");
//訪問public Test(String name,int age)
// Constructor constructor=class1.getConstructor(new Class[]{String.class,int.class});
// Test test=(Test)constructor.newInstance("陳加兵",22);
//訪問預設的構造方法
// Constructor constructor=class1.getConstructor(null);
// Test test=(Test)constructor.newInstance(null);
//訪問private類型的構造方法
Constructor constructor=class1.getDeclaredConstructor(new Class[]{int.class});
constructor.setAccessible(true);
Test test=(Test)constructor.newInstance(new Object[]{1000});
test.display();
成員方法的操作
使用
Class.getMethod()
和Class.getDeclaredMethod()
方法獲取方法,這兩個方法的區別前面已經說過了,註意的是調用私有成員方法的之前一定要設置訪問許可權(method.setAccessible(true)
)
Method類中的其他方法前面也已經說過了,詳細使用請自己嘗試
/*
* 獲取Method對象的兩種方式:
* 1.Method method_set=class1.getMethod("set", new Class[]{String.class,int.class});
* 2.Method method_set=class1.getMethod("set", String.class,int.class);
*
*
* 使用Method.invoke()調用方法的兩種方式
* 1.Object o=method_set.invoke(test, new Object[]{"陳加兵",200});
* 2.Object object=method_set.invoke(test, "陳加兵",2000);
*/
/*
* 獲取公共方法(public):
* 1.Method method=class1.getMethod("display",null); //public void display()
* 2.Method method_set=class1.getMethod("set", new Class[]{String.class,int.class}); //獲取public void set(String name,int age)
*
*
* 獲取私有方法(private,protected)
* 1.Method method_getAge=class1.getDeclaredMethod("getAge", null);
*/
//使用構造方法構造一個Test對象
Class class1 =Class.forName("demo.Test");
Constructor<Test> constructor=class1.getDeclaredConstructor(new Class[]{String.class,int.class});
Test test=constructor.newInstance(new Object[]{"陳加兵",22});
Method method=class1.getMethod("display",null); //獲取public void display()方法的Method對象
Object obj=method.invoke(test, null); //調用方法display
//獲取public void set(String name,int age)
// Method method_set=class1.getMethod("set", new Class[]{String.class,int.class});
Method method_set=class1.getMethod("set", String.class,int.class);
// Object o=method_set.invoke(test, new Object[]{"陳加兵",200});
Object object=method_set.invoke(test, "陳加兵",2000);
test.display();
//獲取私有方法private int getAge()
Method method_getAge=class1.getDeclaredMethod("getAge", null);
method_getAge.setAccessible(true); //必須設置訪問許可權為true
//判斷返回值類型是否為int類型的
if("int".equals(method_getAge.getReturnType().toString()))
{
int ReturnData=(int) method_getAge.invoke(test, null); //調用並且獲取返回值
System.out.println(ReturnData);
}
成員變數的操作
主要使用的
Field
類,前面已經詳細的說過了
/*
* 獲取public修飾的成員變數:
* 1.Field field=class1.getField("name"); //獲取public的成員變數name的Filed對象
*
* 獲取private,protected修飾的成員變數:
* 1. Field field2=class1.getDeclaredField("age");
*/
Class class1=Class.forName("demo.Test");
Test test=new Test("陳加兵",1000);
Field field=class1.getField("name"); //獲取public的成員變數name的Filed對象
System.out.println(field.get(test)); //獲得test對象中的name屬性的值
//獲取private int age的Field對象
Field field2=class1.getDeclaredField("age");
field2.setAccessible(true); //設置訪問許可權
System.out.println(field2.get(test));
參考文章
如果覺得作者寫的好,有所收穫的話,點個關註,推薦一波,文章首發於公眾號!!!