反射2--Field,簡單的實現和部分源碼分析

部分思路來自互聯網html

反射2--Field

public class Person {

    private int age;
    public String name;

    {
        age = 11;
        name = "yoyoyo";
    }

    static {
        System.out.println("Hello");
    }

    public Person() {}

    public Person(String name) {
        this.name = name;
        System.out.println(this.name);
    }

    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

反射獲取參數

public class reflectTest {
    public static void main(String[] args) throws Exception {
        //1.加載class,實例化對象
        Person person = (Person)Class.forName("POJO.Person").newInstance();

        //2.獲取參數
        //getDeclaredField能夠獲取類(不包括超類)中全部做用域(修飾符),所以能夠得到private int age
        Field field = person.getClass().getDeclaredField("age");
        //getField能夠獲取類或超類的公有域(public),因此沒法獲取private int age,但能夠得到public String name;
        //Field field = person.getClass().getField("name");

        //3.當訪問private做用域的參數時,須要setAccessible(true),反射的對象在使用時取消Java語言訪問檢查
        //public的參數能夠不寫setAccessible(true)
        field.setAccessible(true);

        //field.getModifiers()得到參數做用域
        //field.getType()獲取參數類型
        //field.getName()獲取參數名字
        //field.get(obj)獲取值,返回爲object
        System.out.println("first field:"+Modifier.toString(field.getModifiers())+" "+field.getType()+" "+field.getName()+" = "+field.get(person));
        //爲field設置新值,若是是基本類型,會自動解包
        field.set(person,10010);
        System.out.println("last field:"+Modifier.toString(field.getModifiers())+" "+field.getType()+" "+field.getName()+" = "+field.get(person));
    }
}

注意:並非說private的Accessible是false,而public的Accessible就是true(事實是false),實際上field.isAccessible()是獲取此對象的可訪問標誌的值,說人話就是「是否容許get,set」。

@CallerSensitive
    public Field getField(String name)
        throws NoSuchFieldException, SecurityException {

        //checkMemberAccess進行java的安全驗證和訪問權限檢查,
        //Reflection.getCallerClass()能夠獲取到調用這個方法的類
        //PUBLIC容許反射
        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);

        Field field = getField0(name);
        if (field == null) {
            throw new NoSuchFieldException(name);
        }
        return field;
    }
private void checkMemberAccess(int which, Class<?> caller, boolean checkProxyInterfaces) {

        //java安全管理器,進行訪問控制和權限控制,防止運行未知java程序被惡意代碼對系統產生影響
        //https://docs.oracle.com/javase/8/docs/api/java/lang/SecurityManager.html
        final SecurityManager s = System.getSecurityManager();

        //異常則返回null
        if (s != null) {

            //獲取調用類的加載器
            final ClassLoader ccl = ClassLoader.getClassLoader(caller);
            //調用native本地方法,返回classLoader
            final ClassLoader cl = getClassLoader0();

            //PUBLIC=0,DECLARED=1,Member.DECLARED能夠禁止反射  
            if (which != Member.PUBLIC) {

                //若是classLoader和本地獲取的不一致
                if (ccl != cl) {

                    //驗證安全管理器是否有權限
                    //SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION指運行時權限 "能夠訪問以聲明的類成員"
                    //RuntimePermission("accessDeclaredMembers");
                    s.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
                }
            }
            //驗證類是否有包權限
            this.checkPackageAccess(ccl, checkProxyInterfaces);
        }
    }
private Field getField0(String name) throws NoSuchFieldException {
        Field res;
        // 搜索聲明的公共字段
        if ((res = searchFields(privateGetDeclaredFields(true), name)) != null) {
            return res;
        }
        // 遞歸搜索接口
        Class<?>[] interfaces = getInterfaces();
        for (int i = 0; i < interfaces.length; i++) {
            Class<?> c = interfaces[i];
            if ((res = c.getField0(name)) != null) {
                return res;
            }
        }
        // 遞歸搜索父類
        if (!isInterface()) {
            Class<?> c = getSuperclass();
            if (c != null) {
                if ((res = c.getField0(name)) != null) {
                    return res;
                }
            }
        }
        return null;
    }
題外話,關於反射的速度區別

先說結論,「(在常規條件下,也就是個人例子的狀況下)setAccessible(true)將關閉java的安全檢查,大幅度提高反射速度」。java

public class reflectSpeed {
    public static void main(String[] args) throws Exception{
        SecurityManager sm = new SecurityManager();
        sm.checkMemberAccess(Person.class, Member.DECLARED);

        Person person = (Person)Class.forName("main.java.Person").newInstance();
        person.setName("firstName");
        
        Method method = person.getClass().getMethod("getName");
    
        //getName是public,因此不須要setAccessible(true)
        long start = System.currentTimeMillis();
        for(int i = 0;i<10000000;i++){
            method.invoke(person);
        }
        System.out.println("simple:"+(System.currentTimeMillis()-start));

        //看一下setAccessible(true)以後的耗時
        method.setAccessible(true);
        long start1 = System.currentTimeMillis();
        for(int i=0;i<10000000;i++){
            method.invoke(person);
        }
        System.out.println("setAccessible(true):"+(System.currentTimeMillis()-start1));

        //固然不用反射的耗時也做爲對比
        long start2 = System.currentTimeMillis();
        for(int i=0;i<10000000;i++){
            person.getName();
        }
        System.out.println("getName:"+(System.currentTimeMillis()-start2));
    }
}
相關文章
相關標籤/搜索