複習反射

前言

自我理解,反射是動態(運行期)的獲取及使用類的一種方式。

反射的使用場景

個人總結爲3種場景:

  • 在編譯期時,無法得知使用哪個確切的類。
  • 想要打破權限,比如調用私有方法。
  • 想要獲取關於更多該類,其方法或其屬性的更多信息時,比如使用了什麼註解。

反射中重要的類及其重要方法

Class

  • 獲取類的信息
方法 用途
getClasses 獲取所有類(不包含私有類)
getDeclaredClasses 獲取所有類
forName 加載類並初始化其靜態塊
newInstance 根據無參構造函數,獲取該類的實例,若沒有無參構造函數則報錯
getName 獲取類全名
getSimpleName 獲取類名
getClassLoader 獲取其類加載器
getSuperclass 獲取其父類
getPackage 獲取包路徑
isInterface 該類是不是接口類
isArray 該類是不是數組類
isPrimitive 該類是不是私有類
isAnnotation 該類是不是註解類
isAnonymousClass 該類是不是匿名類
isMemberClass 該類是不是內部類
isLocalClass 該類是不是局部類
  • 獲取類,字段,方法,構造函數,註解信息
方法 用途
getFields 獲取所有字段(不包含私有字段)
getDeclaredFields 獲取所有字段
getField 獲取單個字段(不包含私有字段)
getDeclaredField 獲取單個字段
getMethods 獲取所有方法(不包含私有方法)
getDeclaredMethods 獲取所有方法
getMethod 獲取單個方法(不包含私有方法)
getDeclaredMethod 獲取單個方法
getConstructors 獲取所有構造函數(不包含私有構造函數)
getDeclaredConstructors 獲取所有構造函數
getConstructor 獲取單個構造函數
getDeclaredConstructor 獲取單個構造函數(不包含私有構造函數)
getAnnotations 獲取所有註解(不包含私有註解)
getDeclaredAnnotations 獲取所有註解
getAnnotation 獲取單個註解(不包含私有註解)
getDeclaredAnnotation 獲取單個註解

Method

方法 用途
getModifiers 獲取修飾符,返回值類型是int
getReturnType 獲取返回值類型
getName 獲取方法名
getParameterTypes 獲取參數類型
getParameterCount 獲取參數個數
getAnnotation 獲取註解(不含私有註解)
getDeclaredAnnotations 獲取所有註解
getParameterAnnotations 獲取參數的註解
invoke 調用方法

Field

方法 用途
getModifiers 獲取修飾符,返回值類型是int
getType 獲取返回值類型
getName 獲取方法名
get 獲取屬性值,返回值類型是object
getXXX 獲取對應類型的屬性值
set 設置屬性值
setXXX 設置屬性值
setAccessible 設置可以訪問屬性

反射原理

獲取類實例

        Class clazz = Class.forName("test.TestVo");
        // test.TestVo
        System.out.println(clazz.getName());

        // test.TestVo
        System.out.println(test.TestVo.class.getName());

	    // test.TestVo
        TestVo testVo = new TestVo("aa",12);
        System.out.println(testVo.getClass().getName());

以上三種方式的區別是:

方式 區別
Class.forName 可以通過類加載器獲取類實例,並且會做靜態塊初始化
類.class 可以通過類加載器獲取類實例,不會做靜態塊初始化
對象.getClass() 要通過類的對象來獲取實例,說明此時已經加載過類,很大可能是從緩存獲取的類實例

源碼分析

forName

總流程:jvm雙親加載該類,獲取類實例,由於forName0是native方法,這裏就不分析了,就簡單分析loadClass

    public static Class<?> forName(String className)
                throws ClassNotFoundException {
        Class<?> caller = Reflection.getCallerClass();
        // 獲取類加載器,獲取類信息  
        // 如下第二個參數便是 要求初始化靜態塊
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }
     protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
    	// 獲取加載鎖
        synchronized (getClassLoadingLock(name)) {
            // 首先,檢查該類是否已被加載
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                	// 雙親委託加載
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }
				
				// 仍然沒有加載就自己加載
                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

newInstance

public T newInstance()
        throws InstantiationException, IllegalAccessException
    {
        if (System.getSecurityManager() != null) {
            checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
        }

        // NOTE: the following code may not be strictly correct under
        // the current Java memory model.

        // Constructor lookup
        if (cachedConstructor == null) {
            if (this == Class.class) {
                throw new IllegalAccessException(
                    "Can not call newInstance() on the Class for java.lang.Class"
                );
            }
            try {
                Class<?>[] empty = {};
                // 獲取空構造函數(如果沒有空構造函數會報錯)
                final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
                // Disable accessibility checks on the constructor
                // since we have to do the security check here anyway
                // (the stack depth is wrong for the Constructor's
                // security check to work)
                java.security.AccessController.doPrivileged(
                    new java.security.PrivilegedAction<Void>() {
                        public Void run() {
                                c.setAccessible(true);
                                return null;
                            }
                        });
                cachedConstructor = c;
            } catch (NoSuchMethodException e) {
                throw (InstantiationException)
                    new InstantiationException(getName()).initCause(e);
            }
        }
        Constructor<T> tmpConstructor = cachedConstructor;
        // Security check (same as in java.lang.reflect.Constructor)
        int modifiers = tmpConstructor.getModifiers();
        if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
            Class<?> caller = Reflection.getCallerClass();
            if (newInstanceCallerCache != caller) {
                Reflection.ensureMemberAccess(caller, this, null, modifiers);
                newInstanceCallerCache = caller;
            }
        }
        // Run constructor
        try {
        	// 調用無參構造函數,返回實例
            return tmpConstructor.newInstance((Object[])null);
        } catch (InvocationTargetException e) {
            Unsafe.getUnsafe().throwException(e.getTargetException());
            // Not reached
            return null;
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章