Java随笔-生活工作点滴

【Java 笔记】Java 反射相关整理

2019-05-29  本文已影响51人  58bc06151329

文前说明

作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。

本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。

1. Class 类

获取 Class 类对象的三种方法

Class clz = Class.forName("java.lang.String");
Class clz = String.class;
String str = new String("Hello");
Class clz = str.getClass();

Class 类的常用方法

方法名 功能说明
static Class forName(String name) 返回指定类名 name 的 Class 对象。
Object newInstance() 调用缺省构造函数,返回该 Class 对象的一个实例。
getName() 返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。
Class getSuperClass() 返回当前 Class 对象的父类 Class 对象。
Class [] getInterfaces() 获取当前 Class 对象的接口。
ClassLoader getClassLoader() 返回该类的类加载器。

2. Java 反射(Reflection)

2.1 通过反射访问构造函数

Constructor 对象方法名称 说明
isVarArgs() 查看该构造方法是否允许带可变数量的参数,如果允许,返回 true,否则返回 false。
getParameterTypes() 按照声明顺序以 Class 数组的形式获取该构造方法各个参数的类型。
getExceptionTypes() 以 Class 数组的形式获取该构造方法可能抛出的异常类型。
newInstance(Object … initargs) 通过该构造方法利用指定参数创建一个该类型的对象,如果未设置参数则表示采用默认无参的构造方法。
setAccessiable(boolean flag) 如果该构造方法的权限为 private,默认为不允许通过反射利用 netlnstance() 方法创建对象。如果先执行该方法,并将入口参数设置为 true,则允许创建对象。
getModifiers() 获得可以解析出该构造方法所采用修饰符的整数。
public void testConstructor() throws Exception{
        String className = "com.java.test.Person";
        Class<Person> clazz = (Class<Person>) Class.forName(className);
        
        // 获取全部 Constructor 对象
        Constructor<Person> [] constructors = (Constructor<Person>[]) Class.forName(className).getConstructors();
        
        // 获取某一个,需要参数列表
        Constructor<Person> constructor = clazz.getConstructor(String.class, int.class);
        
        // 调用构造器的 newInstance() 方法创建对象
        Object obj = constructor.newInstance("test", 1);                
}
Modifier 对象的静态方法名称 说明
isStatic(int mod) 如果使用 static 修饰符修饰则返回 true,否则返回 false。
isPublic(int mod) 如果使用 public 修饰符修饰则返回 true,否则返回 false。
isProtected(int mod) 如果使用 protected 修饰符修饰则返回 true,否则返回 false。
isPrivate(int mod) 如果使用 private 修饰符修饰则返回 true,否则返回 false。
isFinal(int mod) 如果使用 final 修饰符修饰则返回 true,否则返回 false。
toString(int mod) 以字符串形式返回所有修饰符。
int modifiers = con.getModifiers();    //获取构造方法的修饰符整数。
boolean isPubiic = Modifier.isPublic(modifiers);    //判断修饰符整数是否为 public。
public string ailModifSers = Modifier.toString(modifiers);

2.2 通过反射执行方法(获取方法)

objectCiass.getDeclaredConstructor("max",int.class,String.class);
objectClass.getDeclaredConstructor("max",new Ciass[]{int.class,String.class});
Method 对象静态方法名称 说明
getName() 获取该方法的名称。
getParameterType() 按照声明顺序以 Class 数组的形式返回该方法各个参数的类型。
getRetumType() 以 Class 对象的形式获得该方法的返回值类型。
getExceptionTypes() 以 Class 数组的形式获得该方法可能抛出的异常类型。
invoke(Object obj,Object...args) 利用 args 参数执行指定对象 obj 中的该方法,返回值为 Object 类型。
isVarArgs() 查看该方法是否允许带有可变数量的参数,如果允许返回 true,否 则返回 false。
getModifiers() 获得可以解析出该方法所采用修饰符的整数。
public void testMethod() throws Exception{
        Class clazz = Class.forName("com.java.test.Person");
        
        // 获取取 clazz 对应类中的所有方法,但不能获取 private 方法,且获取从父类继承来的所有方法。
        Method[] methods = clazz.getMethods();
        
        // 获取所有方法,包括私有方法,获取所有声明的方法,且只获取当前类的方法
        methods = clazz.getDeclaredMethods();
       
        // 获取指定的方法,需要参数名称和参数列表,无参则不需要
        //  方法 public void setName(String name)
        Method method = clazz.getDeclaredMethod("setName", String.class);

        //  方法 public void setAge(int age)
        //  方法用于反射,只能对应 int.class,不能对应 Integer.class
        method = clazz.getDeclaredMethod("setAge", int.class);
        
        // 执行方法
        //  invoke 第一个参数表示执行某个对象的方法,剩下的参数是执行方法时需要传入的参数
        // 私有方法的执行,必须在调用 invoke 之前加上 method.setAccessible(true);
        Object obje = clazz.newInstance();
        method.invoke(obje,2);
}

2.3 通过反射访问成员变量

object.getDeciaredField("price");
Field 的方法名称 说明
getName() 获得该成员变量的名称。
getType() 获取表示该成员变量的 Class 对象。
get(Object obj) 获得指定对象 obj 中成员变量的值,返回值为 Object 类型。
set(Object obj,Object value) 将指定对象 obj 中成员变量的值设置为 value。
getlnt(0bject obj) 获得指定对象 obj 中成员类型为 int 的成员变量的值。
setlnt(0bject obj,int i) 将指定对象 obj 中成员变量的值设置为 i。
setFloat(Object obj,float f) 将指定对象 obj 中成员变量的值设置为 f。
getBoolean(Object obj) 获得指定对象 obj 中成员类型为 boolean 的成员变量的值。
setBoolean(Object obj,boolean b) 将指定对象 obj 中成员变量的值设置为 b。
getFloat(Object obj) 获得指定对象 obj 中成员类型为 float 的成员变量的值。
setAccessible(boolean flag) 此方法可以设置是否忽略权限直接访问 private 等私有权限的成员变量。
getModifiers() 获得可以解析出该方法所采用修饰符的整数。
public void testField() throws Exception{
        String className = "com.java.test.Person";        
        Class clazz = Class.forName(className); 
        
        // 获取所有字段,可以获取公用和私有的所有字段,但不能获取父类字段
        Field[] fields = clazz.getDeclaredFields();
        
        // 获取指定字段
        Field field = clazz.getDeclaredField("name");
        
        Person person = new Person("ABC",12);
        
        //获取指定对象的指定字段的值
        Object val = field.get(person);
        
        //设置指定对象的指定对象 Field 值
        field.set(person, "DEF");
        
        // 如果字段是私有的,不管是读值还是写值,都必须先调用 setAccessible(true) 方法
        field.setAccessible(true);
        field = clazz.getDeclaredField("age");
        
}

2.4 通过反射访问注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.METHOD})
public @interface AgeValidator {
    public int min();
    public int max();
}
@AgeValidator(min=18,max=35)
public void setAge(int age) {
        this.age = age;
}
public void testAnnotation() throws Exception{
        String className = "com.java.test.Person";
        
        Class clazz = Class.forName(className);
        Object obj = clazz.newInstance();    
        
        Method method = clazz.getDeclaredMethod("setAge", int.class);
        int val = 6;
        
        //获取指定名称的注解
        Annotation annotation = method.getAnnotation(AgeValidator.class);
        if(annotation != null){
            if(annotation instanceof AgeValidator){
                AgeValidator ageValidator = (AgeValidator) annotation;                
                if(val < ageValidator.min() || val > ageValidator.max()){
                    throw new RuntimeException("年龄非法");
                }
            }
        }        
        method.invoke(obj, 20);
}

3. 实现原理

3.1 Method 的获取

@CallerSensitive
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException {
        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
        Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
        if (method == null) {
            throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
        }
        return method;
}
private static Method searchMethods(Method[] methods,
                                        String name,
                                        Class<?>[] parameterTypes)
{
        Method res = null;
        String internedName = name.intern();
        for (int i = 0; i < methods.length; i++) {
            Method m = methods[i];
            if (m.getName() == internedName
                && arrayContentsEq(parameterTypes, m.getParameterTypes())
                && (res == null
                    || res.getReturnType().isAssignableFrom(m.getReturnType())))
                res = m;
        }

        return (res == null ? res : getReflectionFactory().copyMethod(res));
}
Method copy() {
        // This routine enables sharing of MethodAccessor objects
        // among Method objects which refer to the same underlying
        // method in the VM. (All of this contortion is only necessary
        // because of the "accessibility" bit in AccessibleObject,
        // which implicitly requires that new java.lang.reflect
        // objects be fabricated for each reflective call on Class
        // objects.)
        if (this.root != null)
            throw new IllegalArgumentException("Can not copy a non-root Method");

        Method res = new Method(clazz, name, parameterTypes, returnType,
                                exceptionTypes, modifiers, slot, signature,
                                annotations, parameterAnnotations, annotationDefault);
        res.root = this;
        // Might as well eagerly propagate this if already present
        res.methodAccessor = methodAccessor;
        return res;
}

privateGetDeclaredMethods 的缓存实现

private Method[] privateGetDeclaredMethods(boolean publicOnly) {
        checkInitted();
        Method[] res;
        ReflectionData<T> rd = reflectionData();
        if (rd != null) {
            res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods;
            if (res != null) return res;
        }
        // No cached value available; request value from VM
        res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly));
        if (rd != null) {
            if (publicOnly) {
                rd.declaredPublicMethods = res;
            } else {
                rd.declaredMethods = res;
            }
        }
        return res;
}
private ReflectionData<T> reflectionData() {
        SoftReference<ReflectionData<T>> reflectionData = this.reflectionData;
        int classRedefinedCount = this.classRedefinedCount;
        ReflectionData<T> rd;
        if (useCaches &&
            reflectionData != null &&
            (rd = reflectionData.get()) != null &&
            rd.redefinedCount == classRedefinedCount) {
            return rd;
        }
        // else no SoftReference or cleared SoftReference or stale ReflectionData
        // -> create and replace new instance
        return newReflectionData(reflectionData, classRedefinedCount);
}
private static class ReflectionData<T> {
        volatile Field[] declaredFields;
        volatile Field[] publicFields;
        volatile Method[] declaredMethods;
        volatile Method[] publicMethods;
        volatile Constructor<T>[] declaredConstructors;
        volatile Constructor<T>[] publicConstructors;
        // Intermediate results for getFields and getMethods
        volatile Field[] declaredPublicFields;
        volatile Method[] declaredPublicMethods;
        volatile Class<?>[] interfaces;

        // Value of classRedefinedCount when we created this ReflectionData instance
        final int redefinedCount;

        ReflectionData(int redefinedCount) {
            this.redefinedCount = redefinedCount;
        }
}
private ReflectionData<T> newReflectionData(SoftReference<ReflectionData<T>> oldReflectionData,
                                                int classRedefinedCount) {
        if (!useCaches) return null;

        while (true) {
            ReflectionData<T> rd = new ReflectionData<>(classRedefinedCount);
            // try to CAS it...
            if (Atomic.casReflectionData(this, oldReflectionData, new SoftReference<>(rd))) {
                return rd;
            }
            // else retry
            oldReflectionData = this.reflectionData;
            classRedefinedCount = this.classRedefinedCount;
            if (oldReflectionData != null &&
                (rd = oldReflectionData.get()) != null &&
                rd.redefinedCount == classRedefinedCount) {
                return rd;
            }
        }
}
reflectionDataOffset = objectFieldOffset(fields, "reflectionData");
......
static <T> boolean casReflectionData(Class<?> clazz,
                                             SoftReference<ReflectionData<T>> oldData,
                                             SoftReference<ReflectionData<T>> newData) {
            return unsafe.compareAndSwapObject(clazz, reflectionDataOffset, oldData, newData);
}
if (rd != null) {
      res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods;
      if (res != null) return res;
}
// No cached value available; request value from VM
res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly));
if (rd != null) {
        if (publicOnly) {
             rd.declaredPublicMethods = res;
         } else {
             rd.declaredMethods = res;
         }
}

3.2 Method 的调用

@CallerSensitive
public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException
{
        if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                Class<?> caller = Reflection.getCallerClass();
                checkAccess(caller, clazz, obj, modifiers);
            }
        }
        MethodAccessor ma = methodAccessor;             // read volatile
        if (ma == null) {
            ma = acquireMethodAccessor();
        }
        return ma.invoke(obj, args);
}
private MethodAccessor acquireMethodAccessor() {
        // First check to see if one has been created yet, and take it
        // if so
        MethodAccessor tmp = null;
        if (root != null) tmp = root.getMethodAccessor();
        if (tmp != null) {
            methodAccessor = tmp;
        } else {
            // Otherwise fabricate one and propagate it up to the root
            tmp = reflectionFactory.newMethodAccessor(this);
            setMethodAccessor(tmp);
        }

        return tmp;
}
public MethodAccessor newMethodAccessor(Method var1) {
        checkInitted();
        if (noInflation && !ReflectUtil.isVMAnonymousClass(var1.getDeclaringClass())) {
            return (new MethodAccessorGenerator()).generateMethod(var1.getDeclaringClass(), var1.getName(), var1.getParameterTypes(), var1.getReturnType(), var1.getExceptionTypes(), var1.getModifiers());
        } else {
            NativeMethodAccessorImpl var2 = new NativeMethodAccessorImpl(var1);
            DelegatingMethodAccessorImpl var3 = new DelegatingMethodAccessorImpl(var2);
            var2.setParent(var3);
            return var3;
        }
}
class DelegatingMethodAccessorImpl extends MethodAccessorImpl {
    private MethodAccessorImpl delegate;

    DelegatingMethodAccessorImpl(MethodAccessorImpl var1) {
        this.setDelegate(var1);
    }

    public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
        return this.delegate.invoke(var1, var2);
    }

    void setDelegate(MethodAccessorImpl var1) {
        this.delegate = var1;
    }
}
private static int inflationThreshold = 15;
......
class NativeMethodAccessorImpl extends MethodAccessorImpl {
    private final Method method;
    private DelegatingMethodAccessorImpl parent;
    private int numInvocations;

    NativeMethodAccessorImpl(Method var1) {
        this.method = var1;
    }

    public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
        if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
            MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
            this.parent.setDelegate(var3);
        }

        return invoke0(this.method, var1, var2);
    }

    void setParent(DelegatingMethodAccessorImpl var1) {
        this.parent = var1;
    }

    private static native Object invoke0(Method var0, Object var1, Object[] var2);
}

Inflation 机制


return (MagicAccessorImpl)AccessController.doPrivileged(new PrivilegedAction<MagicAccessorImpl>() {
                public MagicAccessorImpl run() {
                    try {
                        return (MagicAccessorImpl)ClassDefiner.defineClass(var13, var17, 0, var17.length, var1.getClassLoader()).newInstance();
                    } catch (IllegalAccessException | InstantiationException var2) {
                        throw new InternalError(var2);
                    }
                }
});
static Class<?> defineClass(String var0, byte[] var1, int var2, int var3, final ClassLoader var4) {
        ClassLoader var5 = (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
            public ClassLoader run() {
                return new DelegatingClassLoader(var4);
            }
        });
        return unsafe.defineClass(var0, var1, var2, var3, var5, (ProtectionDomain)null);
}

参考资料

https://www.cnblogs.com/chanshuyi/p/head_first_of_reflection.html
http://www.importnew.com/23902.html
http://www.importnew.com/23560.html
http://www.importnew.com/21211.html

上一篇 下一篇

猜你喜欢

热点阅读