這是我參與8月更文挑戰的第3天,活動詳情查看:8月更文挑戰java
前言:目前不少三方框架都有用到反射的知識,本文將要介紹反射經常使用API。json
Java的反射(reflection)機制是指在程序的運行狀態中,能夠構造任意一個類的對象,能夠了解任意一個對象所屬的類,能夠了解任意一個類的成員變量和方法,能夠調用任意一個對象的屬性和方法。這種動態獲取程序信息以及動態調用對象的功能稱爲Java語言的反射機制。反射被視爲動態語言的關鍵。數組
- 優勢
反射提升了Java程序的靈活性和擴展性,下降耦合性,提升自適應能力。它容許程序建立和控制任何類的對象,無需提早硬編碼目標類;反射是其它一些經常使用語言,如C、C++、Fortran 或者Pascal等都不具有的markdown
- 缺點
- 性能問題:使用反射基本上是一種解釋操做,用於字段和方法接入時要遠慢於直接代碼。所以Java反射機制主要應用在對靈活性和擴展性要求很高的系統框架上,普通程序不建議使用。
- 使用反射會模糊程序內部邏輯:程序人員但願在源代碼中看到程序的邏輯,反射等繞過了源代碼的技術,於是會帶來維護問題。反射代碼比相應的直接代碼更復雜。
反射則是一開始並不知道咱們要初始化的類對象是什麼,天然也沒法使用 new關鍵字來建立對象,這時,咱們使用JDK提供的反射API進行反射調用。反射就是在運行狀態中,對於任意一個類,都能知道,調用且改變這個類的全部屬性和方法。app
Java反射機制主要提供瞭如下功能:框架
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);
複製代碼
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() 複製代碼
注意:當咱們獲取到一個方法時,能夠調用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 通配符泛型,得到上下限信息。
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();
}
}
}
複製代碼
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();
}
}
}
複製代碼
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();
}
}
}
複製代碼
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();
}
}
}
複製代碼