簡單瞭解Java反射|Java基礎

這是我參與8月更文挑戰的第3天,活動詳情查看:8月更文挑戰java

前言:目前不少三方框架都有用到反射的知識,本文將要介紹反射經常使用API。json

什麼是反射?

Java的反射(reflection)機制是指在程序的運行狀態中,能夠構造任意一個類的對象,能夠了解任意一個對象所屬的類,能夠了解任意一個類的成員變量和方法,能夠調用任意一個對象的屬性和方法。這種動態獲取程序信息以及動態調用對象的功能稱爲Java語言的反射機制。反射被視爲動態語言的關鍵。數組

優缺點

  • 優勢

反射提升了Java程序的靈活性和擴展性,下降耦合性,提升自適應能力。它容許程序建立和控制任何類的對象,無需提早硬編碼目標類;反射是其它一些經常使用語言,如C、C++、Fortran 或者Pascal等都不具有的markdown

  • 缺點
  1. 性能問題:使用反射基本上是一種解釋操做,用於字段和方法接入時要遠慢於直接代碼。所以Java反射機制主要應用在對靈活性和擴展性要求很高的系統框架上,普通程序不建議使用。
  2. 使用反射會模糊程序內部邏輯:程序人員但願在源代碼中看到程序的邏輯,反射等繞過了源代碼的技術,於是會帶來維護問題。反射代碼比相應的直接代碼更復雜。

反射則是一開始並不知道咱們要初始化的類對象是什麼,天然也沒法使用 new關鍵字來建立對象,這時,咱們使用JDK提供的反射API進行反射調用。反射就是在運行狀態中,對於任意一個類,都能知道,調用且改變這個類的全部屬性和方法。app

Java反射機制主要提供瞭如下功能:框架

  1. 在運行時構造任意一個類的對象
  2. 在運行時獲取或者修改任意一個類所具備的成員變量和方法
  3. 在運行時調用任意一個對象的方法(屬性)

獲取Class對象

  • 經過類名獲取:類名.class()
  • 經過對象獲取:對象名.getClass()
  • 經過全類名獲取: Class.forName(全類名)    classLoader.loadClass(全類名)
public static String str = new String("shixf");
 
    public static void main(String[] args) {
        //1.經過類名獲取
        Class<String> stringClass = String.class;
        //2.經過對象獲取
        Class<? extends String> strClass = str.getClass();
        //3.經過全類名獲取
        try {
            //str.getClass().getName() == java.lang.String
            Class<?> aClass = Class.forName(str.getClass().getName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
複製代碼

判斷是否爲某個類的實例

通常咱們經常用"instanceof" 關鍵字來判斷某個類是否爲一個類的實例,同時也能夠藉助反射中Class對象的  " isInstance()" 方法來判斷是否爲某個類的實例,它是一個native方法。函數

public native boolean isInstance(Object obj);
 
//判斷是否爲某個類的類型
public native boolean isAssignableFrom(Class<?> cls);
複製代碼

反射建立實例對象

  • Class.newInstance()
  • 經過Class獲取Constructor對象,在調用Constructor.newInstance()方法來建立實例.
public static Object createInstance_1(Class cls){
        if(null != cls){
            Object o = null;
            try {
                o = cls.newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return o;
        }
        return null;
    }
 
    public static Object createInstance_2(Class cls){
        //獲取String所對應的Class對象
         Class<?> c = String.class;
         //獲取String類帶一個String參數的構造器
        Constructor constructor = null;
        //根據構造器建立實例
        Object obj = null;
        try {
            constructor = c.getConstructor(String.class);
            obj = constructor.newInstance("23333");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }
複製代碼

獲取構造器信息

/** * @param parameterTypes ...表明可傳入該類型的數組,單個實例,或者不傳參數, * 得到使用特殊的參數類型的public構造函數(包括父類) */
    public Constructor<T> getConstructor(Class<?>... parameterTypes) /** * 得到類的全部公共構造函數 */ public Constructor<?>[] getConstructors() /** * 得到使用特定參數類型的構造函數(包括私有) */ public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) /** * 得到類的全部構造函數 */ public Constructor<?>[] getDeclaredConstructors() 複製代碼

獲取類的成員變量(字段)信息

/** * 獲取命名的公共字段(包含父類的public成員變量) */
public Field getField(String name) /** * 得到類的全部公共字段(包含父類的public成員變量) */ public Field[] getFields() /** * 獲取類自己的屬性成員(包括私有、共有、保護) */ public Field getDeclaredField(String name) /** * 獲取類自己的全部屬性成員(包括私有、共有、保護) */ public Field[] getDeclaredFields() 複製代碼

經過反射調用方法

/** * 使用特定參數類型,得到命名的公共方法 */
public Method getMethod(String name, Class<?>... parameterTypes) /** * 得到類的全部公共方法 */ public Method[] getMethods() /** * 得到類聲明的命名的方法,包括私有的。 */ public Method getDeclaredMethod(String name, Class<?>... parameterTypes) /** * 得到類聲明的全部命名的方法,包括私有的。 */ public Method[] getDeclaredMethods() 複製代碼

java.lang.IllegalArgumentException: wrong number of arguments

注意:當咱們獲取到一個方法時,能夠調用invoke()方法來調用這個方法。以及須要注意的 「wrong number of arguments」異常post

/** * * @param obj * @param args 此處須要注意,該參數爲Object * @return */
public Object invoke(Object obj, Object... args) 複製代碼
public class GetMethod {
 
    private static GetMethod getMethod = new GetMethod();
    private static String[] strArray = {"1","2","3"};
 
 
    public static void main(String[] args) {
        getMethod();
    }
 
    public void printStr(String[] str){
        for (String s : str) {
            System.out.println(s);
        }
    }
 
    public static void getMethod(){
        Class<?> cls = getMethod.getClass();
        try {
            Method printStr = cls.getMethod("printStr",String[].class);
            //此處須要強制轉換爲Object,不然拋出wrong number of arguments
            printStr.invoke(cls.newInstance(),(Object) strArray); 
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
}
複製代碼

利用反射建立數組

數組在 Java 裏是比較特殊的一種類型,它能夠賦值給一個 Object Reference 其中的 Array 類爲 java.lang.reflflect.Array類。咱們經過 Array.newInstance() 建立數組對象,它的原型是 :性能

public static Object newInstance ( Class <?> componentType , int length );
複製代碼

反射獲取泛型真實類型

當咱們對一個泛型類進行反射時,須要獲得泛型中的真是數據類型,來完成如json反序列化的操做。此時須要經過Type體系來完成。Type接口包含了一個實現類(Class)個四個接口,分別是:ui

TypeVariable: 泛型類型變量,能夠泛型上下限等信息。
ParameterizedType 具體的泛型類型,能夠得到元數據中泛型簽名類型(泛型真是類型)
GenericArrayType 當須要描述的類型是泛型類的數組時,好比List[] , map[],此接口會做爲Type的實現。
WildcardType 通配符泛型,得到上下限信息。

TypeVariable

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
 
public class TypeVariableTest<K extends Comparable & Serializable, V> {
 
    private K key;
    private V value;
 
    public static void main(String[] args) {
        try {
            Field fKey = TypeVariableTest.class.getDeclaredField("key");
            Field fValue = TypeVariableTest.class.getDeclaredField("value");
            TypeVariable genericTypeKey = (TypeVariable)fKey.getGenericType();
            TypeVariable genericTypeValue = (TypeVariable)fValue.getGenericType();
 
            System.out.println("genericTypeKey.getName(): " + genericTypeKey.getName());
            System.out.println("genericTypeValue.getName(): " + genericTypeValue.getName());
            System.out.println(genericTypeKey.getGenericDeclaration());//class Reflect.TypeVariableTest
            System.out.println(genericTypeValue.getGenericDeclaration());//class Reflect.TypeVariableTest
            System.out.println("K的上界");
            for (Type bound : genericTypeKey.getBounds()) {
                System.out.println(bound);
                //interface java.lang.Comparable
                //interface java.io.Serializable
            }
            System.out.println("V的上界");
            for (Type bound : genericTypeValue.getBounds()) {
                System.out.println(bound);
                //class java.lang.Object
            }
 
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}
複製代碼

ParameterizedType

public class ParameterizedTypeTest {
 
    Map<String, String> mMap;
 
    public static void main(String[] args) {
        try {
            Field map = ParameterizedTypeTest.class.getDeclaredField("mMap");
 
            System.out.println("get mMap GenericType: " + map.getGenericType());//java.util.Map<java.lang.String, java.lang.String>
 
            ParameterizedType pType = (ParameterizedType)map.getGenericType();
            System.out.println(pType.getRawType());//interface java.util.Map
 
            for (Type actualTypeArgument : pType.getActualTypeArguments()) {
                System.out.println(actualTypeArgument);//倆邊class java.lang.String
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}
複製代碼

GenericArrayType

public class GenericArrayTypeTest<T> {
 
    List<String>[] lists;
 
    public static void main(String[] args) {
        try {
            Field field = GenericArrayTypeTest.class.getDeclaredField("lists");
            GenericArrayType genericArrayType = (GenericArrayType)field.getGenericType();
            System.out.println(genericArrayType.getGenericComponentType());//java.util.List<java.lang.String>
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}
複製代碼

WildcardType

public class WildcardTypeTest {
 
    private List<? extends Number> up;//上限
    private List<? super String> down;//下限
 
    public static void main(String[] args) {
        try {
            Field up = WildcardTypeTest.class.getDeclaredField("up");
            Field down = WildcardTypeTest.class.getDeclaredField("down");
            //先拿到泛型類型
            ParameterizedType parameterizedTypeUp = (ParameterizedType)up.getGenericType();
            ParameterizedType parameterizedTypeDown = (ParameterizedType)down.getGenericType();
 
            //在從泛型類型裏拿到通配符類型
            WildcardType wildcardTypeUp = (WildcardType)parameterizedTypeUp.getActualTypeArguments()[0];
            WildcardType wildcardTypeDown = (WildcardType)parameterizedTypeDown.getActualTypeArguments()[0];
            System.out.println(wildcardTypeUp.getUpperBounds()[0]);//class java.lang.Number
            System.out.println(wildcardTypeDown.getLowerBounds()[0]);//class java.lang.String
 
            System.out.println(wildcardTypeUp);//? extends java.lang.Number
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}
複製代碼
相關文章
相關標籤/搜索