Java反射機制及API使用

原文地址java

反射簡單來講,就是動態加載對象,並對對象進行剖析。在Java中的反射機制是指在運行狀態中,對於任意一個類,都可以知道並獲取這個類的全部屬性和方法。函數

Java反射機制的做用:

  • 在運行時判斷任意一個對象所屬的類。
  • 在運行時判斷任意一個類所具備的成員變量和方法。
  • 在運行時任意調用一個對象的方法
  • 在運行時構造任意一個類的對象

反射機制的優缺點是什麼?

反射機制的優勢就是能夠實現動態建立對象和編譯,體現出很大的靈活性。性能

它的缺點是對性能有影響。使用反射基本上是一種解釋操做,咱們能夠告訴JVM,咱們但願作什麼而且它
知足咱們的要求。這類操做老是慢於只直接執行相同的操做。this

獲取Class對象的三種方式

package com.gyl;

public class Student {
    public int no;
    public String sex;

    private String name;
    private int 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;
    }

    /*
     * 構造方法
     */
    
   Student(String str){  
       System.out.println("(默認)的構造方法 s = " + str);  
   }  
     
   //無參構造方法  
   public Student(){  
       System.out.println("調用了公有、無參構造方法執行了。。。");  
   }  
     
   //有一個參數的構造方法  
   protected Student(char name){  
       System.out.println("姓名:" + name);  
   }  
     
   //有多個參數的構造方法  
   public Student(String name ,int age){  
       System.out.println("姓名:"+name+"年齡:"+ age);//這的執行效率有問題,之後解決。  
   }  
     
   //私有構造方法  
   private Student(int age){  
       System.out.println("私有的構造方法   年齡:"+ age);  
   }
    
}
package com.gyl;

import java.lang.reflect.Constructor;

public class Main {
    public static void main(String[] args) throws ClassNotFoundException {
        Student student = new Student();
        
        /*
         * JAVA反射--獲取Class對象的三種方式
         */
        
        // 經過對象名.getClass()方法獲取
        Class stuClass = student.getClass();
        System.out.println("stuClass is "+stuClass.getName());        
        
        // 經過類名.class方式得到
        Class stuClass1 = Student.class;
        System.out.println("stuClass1 is "+stuClass1.getName());
        System.out.println(stuClass == stuClass1);
        
        // 經過Class.forName()方法得到
        Class stuClass2 = Class.forName("com.gyl.Student");
        System.out.println("stuClass2 is "+stuClass2);
        System.out.println(stuClass1 == stuClass2);
    }
}

Output:
stuClass is com.gyl.Student
stuClass1 is com.gyl.Student
true
stuClass2 is class com.gyl.Student
true
在運行期間,一個類,只有一個Class對象產生。三種方式經常使用第三種,第一種對象都有了還要反射干什麼。第二種須要導入類的包,依賴太強,不導包就拋編譯錯誤。通常都選第三種,一個字符串能夠傳入也可寫在配置文件中等多種方法。

反射API

獲取構造方法

// 返回指定參數類型 public的構造器。 
Constructor<T> getConstructor(類<?>... parameterTypes) 

// 返回指定參數類型的構造器(public, protected, private)。
Constructor<T> getDeclaredConstructor(類<?>... parameterTypes) 

// 返回全部的public類型的構造器
Constructor<?>[] getConstructors() 

// 返回全部的構造器
Constructor<?>[] getDeclaredConstructors()
package com.gyl;

import java.lang.reflect.Constructor;

public class Main {
    public static void main(String[] args) throws ClassNotFoundException {

        // 經過Class.forName()方法得到Class對象
        Class stuClass = Class.forName("com.gyl.Student");
        
        
        System.out.println("************返回全部public構造方法************");
        Constructor[] constructors = stuClass.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        /*
         * Output:
         * ************返回全部public構造方法************
         *    public com.gyl.Student()
         *    public com.gyl.Student(java.lang.String,int)
         */
    
        System.out.println("************全部的構造方法(包括:私有、受保護、默認、公有)***************");  
        Constructor[] constructors2 = stuClass.getDeclaredConstructors();
        for (Constructor constructor : constructors2) {
            System.out.println(constructor);
        }
        /*
         * Output:
         * ************全部的構造方法(包括:私有、受保護、默認、公有)***************
         *    private com.gyl.Student(int)
         *    public com.gyl.Student()
         *    protected com.gyl.Student(char)
         *    public com.gyl.Student(java.lang.String,int)
         *    com.gyl.Student(java.lang.String)
         */
        
        
        Constructor constructor;

        System.out.println("************返回指定類型的 public構造器************");
        try {
            constructor = stuClass.getConstructor(String.class, int.class);
            System.out.println(constructor);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        /*
         * Output:
         * ************返回指定類型的 public構造器************
         * public com.gyl.Student(java.lang.String,int)
         * 
         * 若是指定參數的構造器是非public類型的 則拋出java.lang.NoSuchMethodException異常
         */
          
        System.out.println("************返回指定類型的構造器************");
        try { 
            constructor = stuClass.getDeclaredConstructor(int.class);
            System.out.println(constructor);            // char.class
        } catch (NoSuchMethodException e) {             // String.class, int.class
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        /*
         * Output:
         * ************返回指定類型的構造器************
         * public com.gyl.Student(java.lang.String,int)
         * protected com.gyl.Student(char)
         * private com.gyl.Student(int)
         */
    }
}

獲取變量

// 根據變量名得到對應的變量,訪問權限不限;
Field getDeclaredField(String name) 

// 得到類中全部屬性變量 
Field[] getDeclaredFields()

// 根據變量名獲取對應public類型的屬性變量
Field getField(String name) 

// 獲取類中全部public類型的屬性變量
Field[] getFields()
package com.gyl;

import java.lang.reflect.Field;

public class Main {
    public static void main(String[] args) throws ClassNotFoundException {

        // 經過Class.forName()方法得到Class對象
        Class stuClass = Class.forName("com.gyl.Student");
        
        try {
            Field field1 = stuClass.getField("sex");
            System.out.println(field1);
            
            Field field = stuClass.getDeclaredField("name");
            System.out.println(field);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        /*
         * Output:
         * public java.lang.String com.gyl.Student.sex
         * private java.lang.String com.gyl.Student.name
         * 若是使用getField方法指定了一個非public類型的屬性,則拋出java.lang.NoSuchFieldException異常
         */
        
        Field[] fields1 = stuClass.getFields();
        Field[] fields = stuClass.getDeclaredFields();
        System.out.println("************返回全部public屬性************");
        for (Field field : fields1) {
            System.out.println(field);
        }
        /*
         * Output:
         * ************返回全部public屬性************
         *    public int com.gyl.Student.no
         *    public java.lang.String com.gyl.Student.sex
         */

        System.out.println("************返回全部屬性************");
        for (Field field : fields) {
            System.out.println(field);
        }
        /*
         * Output:
         * ************返回全部屬性************
         *    public int com.gyl.Student.no
         *    public java.lang.String com.gyl.Student.sex
         *    private java.lang.String com.gyl.Student.name
         *    private int com.gyl.Student.age
         */
    }
}

獲取方法

// 獲取「名稱是name,參數是parameterTypes」的public的函數(包括從基類繼承的、從接口實現的全部public函數)
public Method  getMethod(String name, Class[] parameterTypes)

// 獲取所有的public的函數(包括從基類繼承的、從接口實現的全部public函數)
public Method[]  getMethods()

// 獲取「名稱是name,參數是parameterTypes」,而且是類自身聲明的函數,包含public、protected和private方法。
public Method  getDeclaredMethod(String name, Class[] parameterTypes)

// 獲取所有的類自身聲明的函數,包含public、protected和private方法。
public Method[]  getDeclaredMethods()

// 若是這個類是「其它類中某個方法的內部類」,調用getEnclosingMethod()就是這個類所在的方法;若不存在,返回null。
public Method  getEnclosingMethod()
package com.gyl;

import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) throws ClassNotFoundException {

        // 經過Class.forName()方法得到Class對象
        Class stuClass = Class.forName("com.gyl.Student");
        
        Method method;
        try {
//            method = stuClass.getMethod("getName");
            method = stuClass.getDeclaredMethod("getAge");
            System.out.println(method);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        
        
        System.out.println("*********輸出全部方法********");
        Method[] methods = stuClass.getDeclaredMethods();
        for (Method method2 : methods) {
            System.out.println(method2);
        }
        /*
         * Output:
         * public int com.gyl.Student.getAge()
         *    *********輸出全部方法********
         *    public java.lang.String com.gyl.Student.getName()
         *    public void com.gyl.Student.setName(java.lang.String)
         *    void com.gyl.Student.print(java.lang.String)
         *    public int com.gyl.Student.getAge()
         *    public void com.gyl.Student.setAge(int)
         */
    }
}

經過反射越過泛型檢查

泛型用在編譯期,編譯事後泛型擦除(消失掉)。因此是能夠經過反射越過泛型檢查的code

import java.lang.reflect.Method;  
import java.util.ArrayList;  
 
/* 
* 經過反射越過泛型檢查 
*  
* 例如:有一個String泛型的集合,怎樣能向這個集合中添加一個Integer類型的值? 
*/  
public class Demo {  
   public static void main(String[] args) throws Exception{  
       ArrayList<String> strList = new ArrayList<>();  
       strList.add("aaa");  
       strList.add("bbb");  
         
   //  strList.add(100);  
       //獲取ArrayList的Class對象,反向的調用add()方法,添加數據  
       Class listClass = strList.getClass(); //獲得 strList 對象的字節碼 對象  
       //獲取add()方法  
       Method m = listClass.getMethod("add", Object.class);  
       //調用add()方法  
       m.invoke(strList, 100);  
         
       //遍歷集合  
       for(Object obj : strList){  
           System.out.println(obj);
           System.out.println(obj.getClass());
       }  
        /*
         *Output:
         * aaa
         * class java.lang.String
         * bbb
         * class java.lang.String
         * 100
         * class java.lang.Integer
         */
   }  
}

其餘方法請參考Java jdk,本文參考自Java jdk1.8對象

相關文章
相關標籤/搜索