反射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));
    }
}
相关文章
相关标签/搜索