1. 程式人生 > >java-reflect反射

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