java-reflect反射
概述
JAVA反射機制是在執行狀態中;對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。
獲取Class的三種方法
/**
* 獲取Class物件的三種方式
* 1 物件的getClass()方法;
* 2 類的class屬性
* 3 Class類的靜態方法forName(String className)(常用)
*/
public class ReflectDemo {
public static void main(String[ ] args) {
// 通過物件getClass()方法獲取Class物件
Class stuClass1 = new Student().getClass();
// 通過類的class屬性獲取Class物件
Class stuClass2 = Student.class;
// 通過Class類的靜態方法forName()獲取Class物件
try {
//注意此字串必須是真實路徑,就是帶包名的類路徑,包名.類名
Class stuClass3 = Class.forName("ReflectDemo.Student");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
反射獲取構造方法並使用
Student類:
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);
}
}
測試類:
/*
* 通過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('男');
}
}
控制檯輸出:
**********************所有公有構造方法*********************************
public fanshe.Student(java.lang.String,int)
public fanshe.Student(char)
public fanshe.Student()
************所有的構造方法(包括:私有、受保護、預設、公有)***************
private fanshe.Student(int)
protected fanshe.Student(boolean)
public fanshe.Student(java.lang.String,int)
public fanshe.Student(char)
public fanshe.Student()
fanshe.Student(java.lang.String)
*****************獲取公有、無參的構造方法*******************************
con = public fanshe.Student()
呼叫了公有、無參構造方法執行了。。。
******************獲取私有構造方法,並呼叫*******************************
public fanshe.Student(char)
姓名:男
由此可見:
獲取構造方法:
1).批量的方法:
public Constructor[] getConstructors():所有"公有的"構造方法
public Constructor[] getDeclaredConstructors():獲取所有的構造方法(包括私有、受保護、預設、公有)
2).獲取單個的方法,並呼叫:
public Constructor getConstructor(Class… parameterTypes):獲取單個的"公有的"構造方法:
public Constructor getDeclaredConstructor(Class…parameterTypes):獲取"某個構造方法"可以是私有的,或受保護、預設、公有;
呼叫構造方法:Constructor–>newInstance(Object… initargs)
2、newInstance是 Constructor類的方法(管理建構函式的類)
api的解釋為:newInstance(Object…initargs)使用此 Constructor物件表示的構造方法來建立該構造方法的宣告類的新例項,並用指定的初始化引數初始化該例項。它的返回值是T型別,所以newInstance是建立了一個構造方法的宣告類的新例項物件,併為之呼叫。
反射獲取成員變數並呼叫
Student類:
public class Student {
public Student(){}
public String name;
protected int age;
char sex;
private String phoneNum;
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", sex=" + sex
+ ", phoneNum=" + phoneNum + "]";
}
}
測試類:
/*
* 獲取成員變數並呼叫:
*
* 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);
}
}
控制檯輸出:
************獲取所有公有的欄位********************
public java.lang.String fanshe.field.Student.name
************獲取所有的欄位(包括私有、受保護、預設的)********************
public java.lang.String fanshe.field.Student.name
protected int fanshe.field.Student.age
char fanshe.field.Student.sex
private java.lang.String fanshe.field.Student.phoneNum
*************獲取公有欄位**並呼叫***********************************
public java.lang.String fanshe.field.Student.name
驗證姓名:劉德華
**************獲取私有欄位****並呼叫********************************
private java.lang.String fanshe.field.Student.phoneNum
************獲取所有公有的欄位********************
public java.lang.String fanshe.field.Student.name
************獲取所有的欄位(包括私有、受保護、預設的)********************
public java.lang.String fanshe.field.Student.name
protected int fanshe.field.Student.age
char fanshe.field.Student.sex
private java.lang.String fanshe.field.Student.phoneNum
*************獲取公有欄位**並呼叫***********************************
public java.lang.String fanshe.field.Student.name
驗證姓名:劉德華
**************獲取私有欄位****並呼叫********************************
private java.lang.String fanshe.field.Student.phoneNum
驗證電話:Student [name=劉德華, age=0, sex= , phoneNum=18888889999]
由此可見:
呼叫欄位時:
需要傳遞兩個引數:
//產生Student物件
Student stu = new Student();
Object obj = stuClass.getConstructor().newInstance();
//為欄位設定值
f.set(obj,“劉德華”);
//為Student物件中的name屬性賦值
stu.name = “劉德華”
第一個引數:要傳入設定的物件,第二個引數:要傳入實參
反射獲取成員方法並呼叫
Student類:
public class Student {
//**************成員方法***************//
public void show1(String s){
System.out.println("呼叫了:公有的,String引數的show1(): s = " + s);
}
protected void show2(){
System.out.println("呼叫了:受保護的,無參的show2()");
}
void show3(){
System.out.println("呼叫了:預設的,無參的show3()");
}
private String show4(int age){
System.out.println("呼叫了,私有的,並且有返回值的,int引數的show4(): age = " + age);
return "abcd";
}
}
測試類:
import java.lang.reflect.Method;
/*
* 獲取成員方法並呼叫:
*
* 1.批量的:
* public Method[] getMethods():獲取所有"公有方法";(包含了父類的方法也包含Object類)
* public Method[] getDeclaredMethods():獲取所有的成員方法,包括私有的(不包括繼承的)
* 2.獲取單個的:
* public Method getMethod(String name,Class<?>... parameterTypes):
* 引數:
* name : 方法名;
* Class ... : 形參的Class型別物件
* public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
*
* 呼叫方法:
* Method --> public Object invoke(Object obj,Object... args):
* 引數說明:
* obj : 要呼叫方法的物件;
* args:呼叫方式時所傳遞的實參;
*/
public class MethodClass {
public static void main(String[] args) throws Exception {
//1.獲取Class物件
Class stuClass = Class.forName("fanshe.method.Student");
//2.獲取所有公有方法
System.out.println("***************獲取所有的”公有“方法*******************");
stuClass.getMethods();
Method[] methodArray = stuClass.getMethods();
for(Method m : methodArray){
System.out.println(m);
}
System.out.println("***************獲取所有的方法,包括私有的*******************");
methodArray = stuClass.getDeclaredMethods();
for(Method m : methodArray){
System.out.println(m);
}
System.out.println("***************獲取公有的show1()方法*******************");
Method m = stuClass.getMethod("show1", String.class);
System.out.println(m