java之反射機制

空口說反射,很難理解這是個什麼東西,舉個例子就明瞭了。java

假設如今咱們有一張動漫的圖片,咱們經過這張圖片,在大腦中搜索有關記憶,就清楚這張圖片是什麼動漫裏的誰;假設咱們如今有一個名字,在大腦中搜索有關記憶,就天然而然地想到了該名字人物的具體形象,這種思惟過程就是反射。ide

假設一個類已經加載進JVM,那麼,給定該類名,咱們就能夠經過反射來獲取該類的相應信息。學習

具體定義:反射是被視爲動態語言的關鍵,反射機制容許程序在執行期藉助反射API取得任何類的內部信息,並能直接操做在任何對象的內部屬性和方法。this

java反射機制提供的功能:spa

  • 在運行時判斷任意一個對象所屬的類;
  • 在運行時構造任意一個類的對象;
  • 在運行時判斷一個類所具備的成員變量和方法;
  • 在運行時調用任意一個對象的成員變量和方法,生成動態代理;

反射相關的API:代理

  • java.lang.Class:表明一個類
  • java,lang.reflect.Method:表明類的方法
  • java.lang.reflect.Field:表明類的成員變量
  • jav.lang.reflect.Constructor:表明類的構造方法

一。class類code

在Object類中定義瞭如下的方法,此方法將被全部子類繼承:public final Class getClass()。對象

以上方法返回值是一個Class類,此類是java反射的源頭,實際上所謂反射從程序的運行結果來看也很好理解,即:經過對象反射求出類的名稱。blog

反射能夠獲得的信息:某個類的屬性、方法、構造器、某個類到底實現了哪些接口。對於每一個類而言,JRE都爲其保留一個Class類型的對象。一個Class對象包含了特定某個類的有關信息。繼承

  • Class自己也是一個類;
  • Class對象只能由系統創建;
  • 一個類在JVM中只含有一個實例;
  • 一個Class對象對應的是一個加載進JVM中的一個.class文件;
  • 每一個類的實例都會記得本身是由哪一個Class實例所生成;
  • 經過Class能夠完整地獲得一個類中的完整結構;

實例化Class類的四種方式:

  • Class clazz = String.Class();經過類名.class()
  • Class clazz  = p.getClass();經過對象的實例.getClass()
  • Class clazz = Class.forName("java.lang.String);已知一個類的全類名,且在該類的類路徑下,可用過forName()獲取
  • ClassLoader cl = this.getClass().getClassLoader();
    Class clazz4 = cl.loadClass("類的全類名");

2、經過反射調用類的完整結構

Person.java

package ref;

public class Person {
    public String name;
    public int age;
}

Move.java

package ref;

interface Move {
    void move();
}

Study.java

package ref;

public interface Study {
    void study();
}    

Student.java

package ref;

public class Student extends Person implements Move,Study{
    
    public String school;
  private String privateField;
    public void showInfo() {
        System.out.println("學校是"+this.school);
    }

    @Override
    public void study() {
        // TODO Auto-generated method stub
        System.out.println("學習到中學的知識");
    }

    @Override
    public void move() {
        // TODO Auto-generated method stub
        System.out.println("騎自行車上學");
    }
    
    public Student() {
        System.out.println("調用的是Student()");
    }
    
    public Student(String school) {
        this.school = school;
        System.out.println("調用的是Student(String school)");
    }
    private Student(String name,int age) {
        this.name = name;
        this.age = age;
        System.out.println("調用的是Student(String name,int age)");
    }
    
    private void test(String name) {}
    public String testGetSchool() {
        return school;
    }

}

test.java

package ref;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
    public static void main(String[] args) {
        try {
            //這裏是相關代碼
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

1.獲取類的父類和接口

            Class clazz = Class.forName("ref.Student");
            Class superClass = clazz.getSuperclass();
            //獲取父類的名字
            System.out.println("父類:"+superClass.getName());
            //獲取實現的接口
            Class[] interfaces = clazz.getInterfaces();
            for(Class itf:interfaces) {
                System.out.println("接口名字:"+itf.getName());
            }

父類:ref.Person
接口名字:ref.Move
接口名字:ref.Study

2.獲取類的構造方法

//獲取公有的構造方法
            Constructor[] cons = clazz.getConstructors();
            for(Constructor con:cons) {
                System.out.println("--------------------------");
                System.out.println("構造方法:"+con.getName());//獲取構造方法名稱
                //返回1表明public
                System.out.println("構造方法修飾符:"+con.getModifiers());//獲取構造方法修飾符
                //獲取構造方法的參數類型
                Class[] parameterClass = con.getParameterTypes();
                for(Class param:parameterClass){
                    System.out.println("構造方法:"+con.getName()+"的參數類型爲"+param.getName());
                }
                System.out.println("--------------------------");
            }
            //獲取私有的構造方法
            Constructor[] cons2 = clazz.getDeclaredConstructors();
            for(Constructor con:cons2) {
                System.out.println("--------------------------");
                System.out.println("構造方法:"+con.getName());//獲取構造方法名稱
                System.out.println("構造方法修飾符:"+con.getModifiers());//獲取構造方法修飾符
                //獲取構造方法的參數類型
                Class[] parameterClass = con.getParameterTypes();
                for(Class param:parameterClass){
                    System.out.println("構造方法:"+con.getName()+"的參數類型爲"+param.getName());
                }
                System.out.println("--------------------------");
            }

--------------------------
構造方法:ref.Student
構造方法修飾符:1
--------------------------
--------------------------
構造方法:ref.Student
構造方法修飾符:1
構造方法:ref.Student的參數類型爲java.lang.String
--------------------------


 

--------------------------
構造方法:ref.Student
構造方法修飾符:1
--------------------------
--------------------------
構造方法:ref.Student
構造方法修飾符:2
構造方法:ref.Student的參數類型爲java.lang.String
構造方法:ref.Student的參數類型爲int
--------------------------
--------------------------
構造方法:ref.Student
構造方法修飾符:1
構造方法:ref.Student的參數類型爲java.lang.String
--------------------------

3.經過反射來建立對象

                //至關於調用無參構造方法
                Object obj = clazz.newInstance();
                Student stu = (Student) obj;
                //至關於調用Student(String school)構造方法
                Constructor con = clazz.getConstructor(String.class);
                Student stu1 = (Student) con.newInstance("一中");
                //經過反射機制能夠強制獲取私有方法
                Constructor con2 = clazz.getDeclaredConstructor(String.class,int.class);
                //解除私有的封裝
                con2.setAccessible(true);
                Student stu2 = (Student) con2.newInstance("jack",23);
                System.out.println(stu2.name);
                System.out.println(stu2.age);

調用的是Student()
調用的是Student(String school)
調用的是Student(String name,int age)
jack
23

4.獲取類的方法

//獲取全部公有方法
            Method[] ms = clazz.getMethods();
            for(Method m:ms) {
                System.out.println("--------------------------");
                System.out.println("方法名:"+m.getName());
                System.out.println("返回值類型:"+m.getReturnType());
                System.out.println("修飾符:"+m.getModifiers());
                Class[] mrs = m.getParameterTypes();
                if(mrs!=null && mrs.length>0) {
                    for(Class mr:mrs){    
                        System.out.println("方法參數類型:"+mr.getName());
                    }
                }
                System.out.println("--------------------------");
            }
            //獲取全部方法,包括公有和私有
            Method[] ms2 = clazz.getDeclaredMethods();
            for(Method m:ms2) {
                System.out.println("--------------------------");
                System.out.println("方法名:"+m.getName());
                System.out.println("返回值類型:"+m.getReturnType());
                System.out.println("修飾符:"+m.getModifiers());
                Class[] mrs = m.getParameterTypes();
                if(mrs!=null && mrs.length>0) {
                    for(Class mr:mrs){    
                        System.out.println("方法參數類型:"+mr.getName());
                    }
                }
                System.out.println("--------------------------");
            }

--------------------------
方法名:showInfo
返回值類型:void
修飾符:1
--------------------------
--------------------------
方法名:study
返回值類型:void
修飾符:1
--------------------------
--------------------------
方法名:move
返回值類型:void
修飾符:1
--------------------------
--------------------------
方法名:testGetSchool
返回值類型:class java.lang.String
修飾符:1
--------------------------
--------------------------
方法名:wait
返回值類型:void
修飾符:17
--------------------------
--------------------------
方法名:wait
返回值類型:void
修飾符:17
方法參數類型:long
方法參數類型:int
--------------------------
--------------------------
方法名:wait
返回值類型:void
修飾符:273
方法參數類型:long
--------------------------
--------------------------
方法名:equals
返回值類型:boolean
修飾符:1
方法參數類型:java.lang.Object
--------------------------
--------------------------
方法名:toString
返回值類型:class java.lang.String
修飾符:1
--------------------------
--------------------------
方法名:hashCode
返回值類型:int
修飾符:257
--------------------------
--------------------------
方法名:getClass
返回值類型:class java.lang.Class
修飾符:273
--------------------------
--------------------------
方法名:notify
返回值類型:void
修飾符:273
--------------------------
--------------------------
方法名:notifyAll
返回值類型:void
修飾符:273
--------------------------



--------------------------
方法名:test
返回值類型:void
修飾符:2
方法參數類型:java.lang.String
--------------------------

--------------------------
方法名:showInfo
返回值類型:void
修飾符:1
--------------------------
--------------------------
方法名:study
返回值類型:void
修飾符:1
--------------------------
--------------------------
方法名:move
返回值類型:void
修飾符:1
--------------------------
--------------------------
方法名:testGetSchool
返回值類型:class java.lang.String
修飾符:1
--------------------------

5.獲取類的屬性

       //獲取公有屬性
            Field[] fs = clazz.getFields();
            for(Field f:fs) {
                System.out.println("--------------------------");
                System.out.println("屬性名:"+f.getName());
                System.out.println("屬性類型:"+f.getType());
                System.out.println("修飾符:"+f.getModifiers());
                System.out.println("--------------------------");
            }
            //獲取全部屬性
            Field[] fs2 = clazz.getDeclaredFields();
            for(Field f:fs2) {
                System.out.println("--------------------------");
                System.out.println("屬性名:"+f.getName());
                System.out.println("屬性類型:"+f.getType());
                System.out.println("修飾符:"+f.getModifiers());
                System.out.println("--------------------------");
            }

--------------------------
屬性名:school
屬性類型:class java.lang.String
修飾符:1
--------------------------
--------------------------
屬性名:name
屬性類型:class java.lang.String
修飾符:1
--------------------------
--------------------------
屬性名:age
屬性類型:int
修飾符:1
--------------------------



--------------------------
屬性名:school
屬性類型:class java.lang.String
修飾符:1
--------------------------
--------------------------
屬性名:privateField
屬性類型:class java.lang.String
修飾符:2
--------------------------

6.獲取類所在的包

            //獲取類所在的包
            Package p = clazz.getPackage();
            System.out.println(p.getName());

ref

3、經過反射來調用類中指定的方法和屬性

向Student.java中插入如下方法:

    private void test(String name) {
        System.out.println("這是私有的test(String name)方法");
    }

    public void setInfo(String name,String school) {
        this.name = name;
        this.school = school;
        System.out.println("這是公有的setInfo(String name,String school)方法");
    }
    public void setInfo(int age) {
        this.age = age;
        System.out.println("這是公有的setInfo(int age)方法");
    }

1.調用類中指定的方法

                Constructor con = clazz.getConstructor();
                Object obj = con.newInstance();
                //先獲取到方法
                Method m = clazz.getMethod("setInfo", String.class,String.class);
                //再進行調用
                m.invoke(obj, "tom","三中");
                //若是想調用私有的方法
                Method m2 = clazz.getDeclaredMethod("test", String.class);
                m2.setAccessible(true);
                m2.invoke(obj, "jack");
                //調用重載的方法
                Method m3 = clazz.getMethod("setInfo", int.class);
                m3.invoke(obj, 12);
                //調用具備返回值的方法
                Method m4 = clazz.getMethod("testGetSchool");
                String school = (String) m4.invoke(obj);
                System.out.println(school);

調用的是Student()
這是公有的setInfo(String name,String school)方法
這是私有的test(String name)方法
這是公有的setInfo(int age)方法
三中

2.調用類中指定的屬性

                Constructor con = clazz.getConstructor();
                Object obj = con.newInstance();
                Student stu = (Student) obj;
                Field f = clazz.getField("school");
                //對stu屬性school設置值
                f.set(stu,"第三中學");
                String school = (String) f.get(stu);
                System.out.println(school);
                //若是是私有的屬性
                Field f2 = clazz.getDeclaredField("privateField");
                f2.setAccessible(true);
                f2.set(stu,"私有屬性");
                String privateField = (String) f2.get(stu);
                System.out.println(privateField);

調用的是Student()第三中學私有屬性

相關文章
相關標籤/搜索