JAVA反射

java反射機制

JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。

要想解剖一個類,必須先要獲取到該類的字節碼文件對象。而解剖使用的就是Class類中的方法.所以先要獲取到每一個字節碼文件對應的Class類型的對象。

反射就是把java類中的各種成分映射成一個個的Java對象

public class Reflex {

    public static void main(String[] args) {
        /**
         * 獲取Class對象的三種方式:
         * 1.Object ——> getClass();
         * 2.任何數據類型(包括基本數據類型)都有一個“靜態”的class屬性
         * 3.通過Class類的靜態方法:forName(String className)(常用)
         */

        //第一種方式獲取Class對象
        Student student = new Student();
        Class stuClass = student.getClass();
        System.out.println(stuClass.getName());

        //第二種方式獲取Class對象
        Class s = Student.class;
        System.out.println(s == stuClass);

        //第三種方式獲取Class對象
        try {
            Class s1 = Class.forName("com.saliai.red_packet.dto.Student");

            System.out.println(s1 == s );
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }
    }

}

創建一個Student類進行反射常用方法演示

public class Student {
    private String name;
    private int age;

    //(默認的構造方法)
    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);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

調用方法:

獲取構造方法:

1).批量的方法:

public Constructor[] getConstructors():所有"公有的"構造方法
public Constructor[] getDeclaredConstructors():獲取所有的構造方法(包括私有、受保護、默認、公有)

2).獲取單個的方法

public Constructor getConstructor(Class... parameterTypes):獲取單個的"公有的"構造方法:
public Constructor getDeclaredConstructor(Class... parameterTypes):獲取"某個構造方法"可以是私有的,或受保護、默認、公有;

測試代碼示例:

import java.lang.reflect.Constructor;

public class Reflex {

    public static void main(String[] args) {
        /**
         * 通過Class對象可以獲取某個類中的:構造方法、成員變量、成員方法;並訪問成員;
         * 1.獲取構造方法:
         * 1).批量的方法:
         * public Constructor[] getConstructors():所有"公有的"構造方法
         * public Constructor[] getDeclaredConstructors():獲取所有的構造方法(包括私有、受保護、默認、公有)
         * 2).獲取單個的方法,並調用:
         * public Constructor getConstructor(Class... parameterTypes):獲取單個的"公有的"構造方法:
         * public Constructor getDeclaredConstructor(Class... parameterTypes):獲取"某個構造方法"可以是私有的,或受保護、默認、公有;
         *
         * 調用構造方法:
         * Constructor-->newInstance(Object... initargs)
         * 使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,並用指定的初始化參數初始化該實例。
         * 它的返回值是T類型,所以newInstance是創建了一個構造方法的聲明類的新實例對象。併爲之調用
         */
        try {
            Class clazz = Class.forName("com.saliai.red_packet.dto.Student");
            System.out.println("**********************所有公有構造方法*********************************");
            Constructor[] constructors = clazz.getConstructors();
            for (Constructor c:constructors) {
                System.out.println(c);
            }

            System.out.println("************所有的構造方法(包括:私有、受保護、默認、公有)***************");
            constructors = clazz.getDeclaredConstructors();
            for (Constructor c:constructors) {
                System.out.println(c);
            }


            System.out.println("*****************獲取公有、無參的構造方法*******************************");
            Constructor constructor = clazz.getConstructor(null);
            //(1)因爲是無參的構造方法所以類型是一個null,不寫也可以:這裏需要的是一個參數的類型,切記是類型
            //(2)返回的是描述這個無參構造函數的類對象。
            System.out.println("constructor = " + constructor);
            //調用構造方法
            Object obj = constructor.newInstance();
            // System.out.println("obj = " + obj);
            // Student stu = (Student)obj;
            System.out.println("******************獲取私有構造方法,並調用*******************************");
            constructor = clazz.getDeclaredConstructor(char.class);
            System.out.println(constructor);
            //調用構造方法  //暴力訪問(忽略掉訪問修飾符)
            constructor.setAccessible(true);
            obj = constructor.newInstance('男');

        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

運行結果:

**********************所有公有構造方法*********************************
public com.saliai.red_packet.dto.Student(java.lang.String,int)
public com.saliai.red_packet.dto.Student()
public com.saliai.red_packet.dto.Student(char)
************所有的構造方法(包括:私有、受保護、默認、公有)***************
private com.saliai.red_packet.dto.Student(int)
protected com.saliai.red_packet.dto.Student(boolean)
public com.saliai.red_packet.dto.Student(java.lang.String,int)
com.saliai.red_packet.dto.Student(java.lang.String)
public com.saliai.red_packet.dto.Student()
public com.saliai.red_packet.dto.Student(char)
*****************獲取公有、無參的構造方法*******************************
constructor = public com.saliai.red_packet.dto.Student()
調用了公有、無參構造方法執行了。。。
******************獲取私有構造方法,並調用*******************************
public com.saliai.red_packet.dto.Student(char)
姓名:男

獲取成員變量並調用

public class 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 + '\'' +
                '}';
    }
}

測試類:

public class Reflex {

    public static void main(String[] args) {
        /**
         * 獲取成員變量並調用:
         *
         * 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:要爲字段設置的值;
         *
         */
        try {
            Class stuClass = Class.forName("com.saliai.red_packet.dto.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, "18888888888");
            System.out.println("驗證電話:" + stu);

        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

運行結果:

************獲取所有的字段(包括私有、受保護、默認的)********************
public java.lang.String com.saliai.red_packet.dto.Student.name
protected int com.saliai.red_packet.dto.Student.age
char com.saliai.red_packet.dto.Student.sex
private java.lang.String com.saliai.red_packet.dto.Student.phoneNum
*************獲取公有字段**並調用***********************************
public java.lang.String com.saliai.red_packet.dto.Student.name
驗證姓名:劉華
**************獲取私有字段****並調用********************************
private java.lang.String com.saliai.red_packet.dto.Student.phoneNum
驗證電話:Student{name='劉德華', age=0, sex= , phoneNum='18888888888'}

獲取成員方法並調用

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

測試類:

public class Reflex {

    public static void main(String[] args) {
        /**
         * 獲取成員方法並調用:
         *
         * 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:調用方式時所傳遞的實參;
         */
        try {
            Class stuClass = Class.forName("com.saliai.red_packet.dto.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);
            //實例化一個Student對象
            Object obj = stuClass.getConstructor().newInstance();
            m.invoke(obj, "劉德華");
            System.out.println("***************獲取私有的show4()方法******************");
            m = stuClass.getDeclaredMethod("show4", int.class);
            System.out.println(m);
            m.setAccessible(true);//解除私有限定
            Object result = m.invoke(obj, 20);//需要兩個參數,一個是要調用的對象(獲取有反射),一個是實參
            System.out.println("返回值:" + result);

        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

運行結果:

***************獲取所有的”公有“方法*******************
public void com.saliai.red_packet.dto.Student.show1(java.lang.String)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
***************獲取所有的方法,包括私有的*******************
protected void com.saliai.red_packet.dto.Student.show2()
void com.saliai.red_packet.dto.Student.show3()
public void com.saliai.red_packet.dto.Student.show1(java.lang.String)
private java.lang.String com.saliai.red_packet.dto.Student.show4(int)
***************獲取公有的show1()方法*******************
public void com.saliai.red_packet.dto.Student.show1(java.lang.String)
調用了:公有的,String參數的show1(): s = 劉德華
***************獲取私有的show4()方法******************
private java.lang.String com.saliai.red_packet.dto.Student.show4(int)
調用了,私有的,並且有返回值的,int參數的show4(): age = 20
返回值:abcd

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章