Java笔记(十九) 反射
反射
反射是在運行時獲取類型的信息,再根據這些信息進行操作。
一、Class類
每個已加載的類在內存中都有一份類信息,每個對象都有指向它的類信息的引用。
在Java中,類信息對應的類就是java.lang.Class(注意不是小寫的class),Object方法:
public final native Class<?> getClass()Class是泛型類,還有一種獲取Class方法:
Class<Date> cls = Date.class接口也有Class對象:
Class<Comparable> cls = Comparable.class;基本類型沒有getClass方法,但也都有對應的Class對象,類型參數為相應的包裝類型:
Class<Integer> intCls = int.class; Class<Byte> byteCls = byte.class; Class<Character> charCls = char.class; Class<Double> doubleCls = double.class;void也有:
Class<Void> voidCls = void.class;對于數組每個維度都有一個:
String[] strArr = new String[10]; int[][] twoDimArr = new int[3][2]; int[] oneDimArr = new int[10]; Class<? extends String[]> strArrCls = strArr.getClass(); Class<? extends int[][]> twoDimArrCls = twoDimArr.getClass(); Class<? extends int[]> oneDimArrCls = oneDimArr.getClass();根據類名加載Class:
Class<?> cls = Class.forName("java.util.HashMap");下面介紹Class的一些方法。
1.名稱信息
public String getName() public String getSimpleName() public String getCanonicalName() public Package getPackage()2.字段信息
類中定義的靜態和實例變量被稱為字段,在Java中用Field表示,位于包java.lang.reflect。Class中獲取字段信息的方法:
//返回所有的public字段,包括其父類的,如果沒有字段,返回空數組 public Field[] getFields() //返回本類聲明的所有字段,包括非public的,但不包括父類的 public Field[] getDeclaredFields() //返回本類或者父類中指定名字的public字段,找不到拋異常 public Field getField(String name) //根據名字找本類的字段 public Field getDeclaredField(String name)Field也有很多方法獲取字段信息:
//獲取字段名稱 public String getName() //判斷當前程序是否有該字段的訪問權限 public boolean isAccessible() //flag設為true表示允許讀寫非public的字段 public void setAccessible(boolean flag) //獲取指定對象obj中該字段的值 public Object get(Object obj) //將指定對象obj中該字段的值設為value public void set(Object obj, Object value)在上面的set/get方法中,對于靜態變量,obj被忽略,設置為null。
其他方法:
public int getModifiers() public Class<?> getType() public void setBoolean(Object obj, boolean z) public boolean getBoolean(Object obj) public void setDouble(Object obj, double d) public double getDouble(Object obj) public <T extends Annotation> T getAnnotation(Class<T> annotationClass) public Annotation[] getDeclaredAnnotations() try {Field f = Test.class.getDeclaredField("MAX_COUNT");int mod = f.getModifiers();System.out.println(Modifier.toString(mod)); //private static finalSystem.out.println(Modifier.isPublic(mod));//false} catch (NoSuchFieldException e) {e.printStackTrace();}3.方法信息
用類Method表示,Class有如下方法:
public Method[] getMethods() public Method[] getDeclaredMethods() public Method getMethod(String name, Class<?>... parameterTypes) public Method getDeclaredMethod(String name, Class<?>... parameterTypes)Method類中的方法有:
public String getName() public void setAccessible(boolean flag) public Object invoke(Object obj, Object... args) throws IllegalAccessException, Illegal-ArgumentException, InvocationTargetException對于invoke方法,如果Method為靜態方法,obj被忽略,傳入null。args可以為null,
或者為空數組。方法的返回值被包裝為Object返回,如果實際方法調用拋出異常,異常
被包裝為InvocationTargetException重新拋出,可以通過getCause方法得到原異常。
4.創建對象和構造方法
Class有一個可以創建對象的方法:
public T newInstance() throws InstantiationException, IllegalAccessException它會調用默認的構造方法,如果沒有,拋出異常。
newInstance()方法只能使用默認的構造方法。Class還有一些獲取其他構造方法的方法:
public Constructor<?>[] getConstructors() public Constructor<?>[] getDeclaredConstructors() public Constructor<T> getConstructor(Class<?>... parameterTypes) public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)類Constructor表示構造方法,通過它可以創建對象,方法為:
public T newInstance(Object ... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException例子:
Constructor<StringBuilder> contructor= StringBuilder.class .getConstructor(new Class[]{int.class}); StringBuilder sb = contructor.newInstance(100);5.類型檢查和轉換
如果檢查的類型是動態的,可以使用Class類的如下方法:
public native boolean isInstance(Object obj); Class cls = Class.forName("java.util.ArrayList");if(cls.isInstance(list)){System.out.println("array list"); }動態的強制類型轉換,可以使用Class方法:
public T cast(Object obj)判斷Class之間的關系
//檢查參數類型cls能否賦值給當前class類型的變量 public native boolean isAssignableFrom(Class<?> cls);6.Class的類型信息
public native boolean isArray() public native boolean isPrimitive() //是否是基礎類型 public native boolean isInterface() public boolean isEnum() public boolean isAnnotation() public boolean isAnonymousClass() //是否是匿名類 public boolean isMemberClass() //是否是成員類,成員類定義在方法外,不是匿名類 public boolean isLocalClass() //是否是本地類,本地類定義在方法內,不是匿名類7.類的聲明信息
Class的其他方法:
public native int getModifiers() public native Class<? super T> getSuperclass() //對于類,為自己聲明實現的所有接口,對于接口為直接擴展的接口,不包括父類繼承的 public native Class<?>[] getInterfaces(); //自己聲明的注解 public Annotation[] getDeclaredAnnotations() //所有注解包括繼承得到的 public Annotation[] getAnnotations() //獲取或者檢查指定類型的注解 public <A extends Annotation> A getAnnotation(Class<A> annotationClass) public boolean isAnnotationPresent( Class<? extends Annotation> annotationClass)8.類的加載
Class有兩個靜態方法,可以根據類名加載類:
public static Class<?> forName(String className) //這里的className與Class.getName()返回的值一致 public static Class<?> forName(String name, boolean initialize, ClassLoader loader) //inntialize表示加載后,是否執行類的初始化代碼(如static語句塊)第一個方法相當于調用:
Class.forName(className, true, currentLoader)9.反射與數組
對于數組類型,有一個專門的方法,可以獲取它的元素類型:
public native Class<?> getComponentType()例如:
String[] arr = new String[]{}; System.out.println(arr.getClass().getComponentType());//class java.lang.Stringjava.lang.reflect包中有一個針對數組的專門類Array,提供了對于數組的一些反射支持,主要方法有:
//創建指定元素類型、長度的數組 public static Object newInstance(Class<?> componentType, int length) //創建多維數組 public static Object newInstance(Class<?> componentType, int... dimensions) //獲取數組array指定索引位置index處的值 public static native Object get(Object array, int index) //修改數組array指定的索引位置的index處的值為value public static native void set(Object array, int index, Object value) //返回數組的長度 public static native int getLength(Object array)Array也支持各種基本類型操作數組元素
public static native double getDouble(Object array, int index) public static native void setDouble(Object array, int index, double d) public static native void setLong(Object array, int index, long l) public static native long getLong(Object array, int index)10.反射與枚舉
枚舉類型也有一個專門的方法,可以獲取所有的枚舉常量:
public T[] getEnumConstants()二、反射與泛型
我們曾經說過,泛型參數在運行時會被擦除,其實在類信息
Class中仍然有關于泛型的一些信息,可以通過反射得到。
獲取類的泛型參數的Class實例方法:
public TypeVariable<Class<T>>[] getTypeParameters()Field有如下方法:
public Type getGenericType()Method有如下方法:
public Type getGenericReturnType() public Type[] getGenericParameterTypes() public Type[] getGenericExceptionTypes()Constructor有如下方法:
public Type[] getGenericParameterTypes()其中Type是一個接口,Class實現了Type,Type的其他子接口還有:
TypeVariable:類型參數,可以有上界,比如T extends Number
ParameterizedType :參數化類型,有原始類型和具體的類型參數比如,List
WildcardType :通配符類型,比如?、?extends Number、 ? super Integer
三、總結
不建議使用反射,理由如下:
1)沒有編譯器檢測,容易出錯
2)性能相對低下
所以,如果能用接口實現同樣的靈活性,就不要使用反射。
轉載于:https://www.cnblogs.com/Shadowplay/p/9986809.html
總結
以上是生活随笔為你收集整理的Java笔记(十九) 反射的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深入理解 sudo 与 su 之间的区别
- 下一篇: 如何知道 CPU 是否支持虚拟化技术(V