反射是框架的靈魂!但先要獲取到每一個位元組碼檔案對應的Class型別的物件.
Java反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取類的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。
反射就是把Java類中的各種成分對映成一個個的Java物件,所以運用反射必須依賴於目標類是否被載入,即首先需要經行類載入,獲取該類在Java記憶體(方法區)中這個唯一例項才可
Class 類的例項表示正在執行的 Java 應用程式中的類和介面。也就是jvm中有N多的例項每個類都有該Class物件。(包括基本資料型別)
Class 沒有公共構造方法。Class 物件是在載入類時由 Java 虛擬機器以及透過呼叫類載入器中的defineClass 方法自動構造的。也就是這不需要我們自己去處理建立,JVM已經幫我們建立好了。
3.1 獲取Class物件的三種方式
Object->getClass();
public class Main {
public static void main(String[] args){
Parent parent = new Parent();
Class pclass = parent.getClass();
//是因為Object類中的getClass方法、因為所有類都繼承Object類。從而呼叫Object類來獲取
}
}
class Parent{
}
任何資料型別都有靜態class屬性
public class Main {
public static void main(String[] args){
Class pclass = Parent.class;
// 任何資料型別(包括基本資料型別)都有一個“靜態”的class屬性
}
}
class Parent{
}
Class.forName(String className)
public class Main {
public static void main(String[] args){
Class pclass = Class.forName("ddx.Main");
//透過Class類的靜態方法:forName(String className)(常用)
}
}
class Parent{
}
三種方式常用第三種,第一種物件都有了還要反射干什麼。第二種需要匯入類的包,依賴太強,不導包就拋編譯錯誤。一般都第三種,一個字串可以傳入也可寫在配置檔案中等多種方法。
2、透過反射獲取構造方法並使用:
package fanshe;
public class Student {
//---------------構造方法-------------------
//(預設的構造方法)
Student(String str){
System.out.println("(預設)的構造方法 s = " + str);
}
//無參構造方法
public Student(){
System.out.println("呼叫了公有、無參構造方法執行了。。。");
}
//有一個引數的構造方法
public Student(char name){
System.out.println("姓名:" + name);
}
//有多個引數的構造方法
public Student(String name ,int age){
System.out.println("姓名:"+name+"年齡:"+ age);//這的執行效率有問題,以後解決。
}
//受保護的構造方法
protected Student(boolean n){
System.out.println("受保護的構造方法 n = " + n);
}
//私有構造方法
private Student(int age){
System.out.println("私有的構造方法 年齡:"+ age);
}
}
測試類:
package fanshe;
import java.lang.reflect.Constructor;
/*
* 透過Class物件可以獲取某個類中的:構造方法、成員變數、成員方法;並訪問成員;
*
* 1.獲取構造方法:
* 1).批次的方法:
* public Constructor[] getConstructors():所有"公有的"構造方法
public Constructor[] getDeclaredConstructors():獲取所有的構造方法(包括私有、受保護、預設、公有)
* 2).獲取單個的方法,並呼叫:
* public Constructor getConstructor(Class... parameterTypes):獲取單個的"公有的"構造方法:
* public Constructor getDeclaredConstructor(Class... parameterTypes):獲取"某個構造方法"可以是私有的,或受保護、預設、公有;
*
* 呼叫構造方法:
* Constructor-->newInstance(Object... initargs)
*/
public class Constructors {
public static void main(String[] args) throws Exception {
//1.載入Class物件
Class clazz = Class.forName("fanshe.Student");
//2.獲取所有公有構造方法
System.out.println("**********************所有公有構造方法*********************************");
Constructor[] conArray = clazz.getConstructors();
for(Constructor c : conArray){
System.out.println(c);
}
System.out.println("************所有的構造方法(包括:私有、受保護、預設、公有)***************");
conArray = clazz.getDeclaredConstructors();
for(Constructor c : conArray){
System.out.println(c);
}
System.out.println("*****************獲取公有、無參的構造方法*******************************");
Constructor con = clazz.getConstructor(null);
//1>、因為是無參的構造方法所以型別是一個null,不寫也可以:這裡需要的是一個引數的型別,切記是型別
//2>、返回的是描述這個無參建構函式的類物件。
System.out.println("con = " + con);
//呼叫構造方法
Object obj = con.newInstance();
// System.out.println("obj = " + obj);
// Student stu = (Student)obj;
System.out.println("******************獲取私有構造方法,並呼叫*******************************");
con = clazz.getDeclaredConstructor(char.class);
System.out.println(con);
//呼叫構造方法
con.setAccessible(true);//暴力訪問(忽略掉訪問修飾符)
obj = con.newInstance('男');
}
}
4.獲取成員變數並呼叫
package fanshe.field;
import java.lang.reflect.Field;
/*
* 獲取成員變數並呼叫:
*
* 1.批次的
* 1).Field[] getFields():獲取所有的"公有欄位"
* 2).Field[] getDeclaredFields():獲取所有欄位,包括:私有、受保護、預設、公有;
* 2.獲取單個的:
* 1).public Field getField(String fieldName):獲取某個"公有的"欄位;
* 2).public Field getDeclaredField(String fieldName):獲取某個欄位(可以是私有的)
*
* 設定欄位的值:
* Field --> public void set(Object obj,Object value):
* 引數說明:
* 1.obj:要設定的欄位所在的物件;
* 2.value:要為欄位設定的值;
*
*/
public class Fields {
public static void main(String[] args) throws Exception {
//1.獲取Class物件
Class stuClass = Class.forName("fanshe.field.Student");
//2.獲取欄位
System.out.println("************獲取所有公有的欄位********************");
Field[] fieldArray = stuClass.getFields();
for(Field f : fieldArray){
System.out.println(f);
}
System.out.println("************獲取所有的欄位(包括私有、受保護、預設的)********************");
fieldArray = stuClass.getDeclaredFields();
for(Field f : fieldArray){
System.out.println(f);
}
System.out.println("*************獲取公有欄位**並呼叫***********************************");
Field f = stuClass.getField("name");
System.out.println(f);
//獲取一個物件
Object obj = stuClass.getConstructor().newInstance();//產生Student物件--》Student stu = new Student();
//為欄位設定值
f.set(obj, "劉德華");//為Student物件中的name屬性賦值--》stu.name = "劉德華"
//驗證
Student stu = (Student)obj;
System.out.println("驗證姓名:" + stu.name);
System.out.println("**************獲取私有欄位****並呼叫********************************");
f = stuClass.getDeclaredField("phoneNum");
System.out.println(f);
f.setAccessible(true);//暴力反射,解除私有限定
f.set(obj, "18888889999");
System.out.println("驗證電話:" + stu);
}
}
4、獲取成員方法並呼叫
5、反射main方法
本作品採用《CC 協議》,轉載必須註明作者和本文連結