反射有性能損失,損失在哪裏?Class.getDeclaredMethod與Class.getMethod方法的區別是什麼?

反射有性能損失,損失在哪裏?

反射的執行過程:
ClassLoader加載一個類會把類信息加載到JVM中,反射方法時,會動態解析Class需要獲取方法中的數據組成Method對象,反射執行的時候會通過Method對象執行需要執行的方法

整個過程會產生額外的對象,並且在執行方法時(Method.invoke),每次執行都會檢查方法的可見性,相當於用Method對象作爲中間者來執行,這種方式比直接執行慢。

反射是基於程序集和元數據的,在使用反射的時候,會搜索元數據,而元數據是基於字符串的,並且無法預編譯,所以這一系列操作對性能有影響

Method.invoke方法會對參數做裝箱拆箱操作,invoke方法的參數是Object可變長參數,如果方法參數是基本數據類型的話,需要在此裝箱,成爲基本類型的包裝類型,會產生額外對象,在native方法中,需要把包裝類拆箱成爲基本類型。當調用次數達到一定量的時候,還會觸發GC。

Method.invoke代碼

    @CallerSensitive
    // Android-changed: invoke(Object, Object...) implemented natively.
    @FastNative
    public native Object invoke(Object obj, Object... args)
            throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;

其實簡單少量的反射並不會對應用性能有太大影響,可以忽略不計,反射大概比直接調用慢50~100倍,但是需要你在執行100萬遍的時候纔會有所感覺,如果只是偶爾調用一下反射,請忘記反射帶來的性能影響。
可以參考這篇文章:反射是否真的會讓你的程序性能降低?

Class.getDeclaredMethod與Class.getMethod方法的區別是什麼?

getDeclaredMethod(String name, Class<?>… parameterTypes)
獲取當前類中的成員方法,不管是否是public,不包括父類繼承的方法

getMethod(String name, Class<?>… parameterTypes)
獲取public的成員方法,包括從父類繼承的方法

getDeclaredField(String name)
用於獲取當前類中的變量,不管是否是public,不包括父類繼承的方法

getField(String name)
用於獲取public的成員變量,包括從父類繼承的成員變量

附上
getMethod、getDeclaredMethod源碼

    @CallerSensitive
    public Method getMethod(String name, Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException {
        return getMethod(name, parameterTypes, true);//true:遞歸獲取父類public方法
    }
    
	@CallerSensitive
    public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException {
        return getMethod(name, parameterTypes, false);
    }

    private Method getMethod(String name, Class<?>[] parameterTypes, boolean recursivePublicMethods)
            throws NoSuchMethodException {
        if (name == null) {
            throw new NullPointerException("name == null");
        }
        if (parameterTypes == null) {
            parameterTypes = EmptyArray.CLASS;
        }
        for (Class<?> c : parameterTypes) {
            if (c == null) {
                throw new NoSuchMethodException("parameter type is null");
            }
        }
        //getPublicMethodRecursive獲取public的成員方法,包括從父類繼承的方法
        //getDeclaredMethodInternal獲取當前類中的成員方法,不管是否是public,不包括父類繼承的方法
        Method result = recursivePublicMethods ? getPublicMethodRecursive(name, parameterTypes)
                                               : getDeclaredMethodInternal(name, parameterTypes);
        // Fail if we didn't find the method or it was expected to be public.
        if (result == null ||
        								//檢查方法的可見性
            (recursivePublicMethods && !Modifier.isPublic(result.getAccessFlags()))) {
            throw new NoSuchMethodException(name + " " + Arrays.toString(parameterTypes));
        }
        return result;
    }
    //由getMethod方法調用,獲取public的成員方法,包括從父類繼承的方法
    private Method getPublicMethodRecursive(String name, Class<?>[] parameterTypes) {
        // search superclasses
        for (Class<?> c = this; c != null; c = c.getSuperclass()) {
            Method result = c.getDeclaredMethodInternal(name, parameterTypes);
            if (result != null && Modifier.isPublic(result.getAccessFlags())) {
                return result;
            }
        }

        return findInterfaceMethod(name, parameterTypes);
    }

getDeclaredField源碼

 /**
     * Returns a {@code Field} object that reflects the specified declared
     * field of the class or interface represented by this {@code Class}
     * object. The {@code name} parameter is a {@code String} that specifies
     * the simple name of the desired field.
 */
    @FastNative
    public native Field getDeclaredField(String name) throws NoSuchFieldException;

getDeclaredFields 源碼

/**
     * Returns an array of {@code Field} objects reflecting all the fields
     * declared by the class or interface represented by this
     * {@code Class} object. This includes public, protected, default
     * (package) access, and private fields, but excludes inherited fields.
     * 返回public、protected,default access和private字段,但是不包括繼承的字段 
*/
    @FastNative
    public native Field[] getDeclaredFields();

getField 源碼

   /**
     * Returns a {@code Field} object that reflects the specified public member
     * field of the class or interface represented by this {@code Class}
     * object. The {@code name} parameter is a {@code String} specifying the
     * simple name of the desired field.
   */
    public Field getField(String name)
        throws NoSuchFieldException {
        if (name == null) {
            throw new NullPointerException("name == null");
        }
        Field result = getPublicFieldRecursive(name);
        if (result == null) {
            throw new NoSuchFieldException(name);
        }
        return result;
    }
    /**
     * The native implementation of the {@code getField} method.
     *
     * @throws NullPointerException
     *            if name is null.
     * @see #getField(String)
     */
    @FastNative
    private native Field getPublicFieldRecursive(String name);

getFields()源碼

    @CallerSensitive
    public Field[] getFields() throws SecurityException {
        List<Field> fields = new ArrayList<Field>();
        getPublicFieldsRecursive(fields);
        return fields.toArray(new Field[fields.size()]);
    }

    /**
     * Populates {@code result} with public fields defined by this class, its
     * superclasses, and all implemented interfaces.
     */
    private void getPublicFieldsRecursive(List<Field> result) {
        // search superclasses
        for (Class<?> c = this; c != null; c = c.superClass) {
            Collections.addAll(result, c.getPublicDeclaredFields());
        }

        // search iftable which has a flattened and uniqued list of interfaces
        Object[] iftable = ifTable;
        if (iftable != null) {
            for (int i = 0; i < iftable.length; i += 2) {
                Collections.addAll(result, ((Class<?>) iftable[i]).getPublicDeclaredFields());
            }
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章