오늘
Java Basics 칼럼에서는 JVM 반영 원리 기술 사항에 대한 매우 자세한 요약을 소개합니다.
1. JAVA 반사 메커니즘은 실행 상태
모든 클래스에 대해 이 클래스의 모든 속성과 메서드를 알 수 있습니다.
모든 개체에 대해 호출할 수 있습니다.
이러한 정보의 동적 획득과 객체 메서드를 동적으로 호출하는 기능을 Java 언어의 반사 메커니즘이라고 합니다.
(속성이 비공개인 경우 외부 세계는 일반적인 상황에서 속성 값을 조작하는 것이 허용되지 않습니다. 여기서 Field 클래스의 setAccessible(true) 메서드를 사용하여 일시적으로 속성을 열 수 있습니다. 연산 권한)
예제 API:
Class.forName("com.my.reflectTest").newInstance()复制代码
을 얻으세요. 먼저, 클래스 정보를 얻기 위해 java.lang.Class의 정적 메소드를 호출합니다!
참고: 클래스 정보를 얻기 위한 forName() 반사는 구현을 Java에 맡기지 않고 로드를 위해 jvm에 맡깁니다! L 주로 ClassLoader를 먼저 가져온 다음 Native 메서드를 호출하여 정보를 얻습니다. 로딩 클래스는 ClassLoader를 클래스로 복구하여 로드하는 것입니다.
@CallerSensitive public static Class<?> forName(String className) throws ClassNotFoundException { // 先通过反射,获取调用进来的类信息,从而获取当前的 classLoader Class<?> caller = Reflection.getCallerClass(); // 调用native方法进行获取class信息 return forName0(className, true, ClassLoader.getClassLoader(caller), caller); }复制代码
2.java.lang.ClassLoader----loadClass()
// java.lang.ClassLoader protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { // 先获取锁 synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded // 如果已经加载了的话,就不用再加载了 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; } } protected Object getClassLoadingLock(String className) { Object lock = this; if (parallelLockMap != null) { // 使用 ConcurrentHashMap来保存锁 Object newLock = new Object(); lock = parallelLockMap.putIfAbsent(className, newLock); if (lock == null) { lock = newLock; } } return lock; } protected final Class<?> findLoadedClass(String name) { if (!checkName(name)) return null; return findLoadedClass0(name); }复制代码
newInstance() 其实相当于调用类的无参构造函数,主要做了三件事复制代码
// 首先肯定是 Class.newInstance @CallerSensitive 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 // newInstance() 其实相当于调用类的无参构造函数,所以,首先要找到其无参构造器 if (cachedConstructor == null) { if (this == Class.class) { // 不允许调用 Class 的 newInstance() 方法 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; } }复制代码
private Constructor<T> getConstructor0(Class<?>[] parameterTypes, int which) throws NoSuchMethodException { // 获取所有构造器 Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC)); for (Constructor<T> constructor : constructors) { if (arrayContentsEq(parameterTypes, constructor.getParameterTypes())) { return getReflectionFactory().copyConstructor(constructor); } } throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes)); }复制代码5.privateGetDeclaredConstructors()를 발생시키고 생성자의 모든 주요 단계를 가져옵니다. 1. 먼저 캐시에서 가져옵니다. 2. 캐시가 없으면 jvm에서 검색하여 캐시에 저장합니다. 캐시는 메모리를 사용할 수 있는지 확인하기 위해 소프트 참조를 사용합니다. 또한 캐시 저장을 위해 relactionData()를 사용합니다. ; ReflectionData의 데이터 구조는 다음과 같습니다!
// 获取当前类所有的构造方法,通过jvm或者缓存 // Returns an array of "root" constructors. These Constructor // objects must NOT be propagated to the outside world, but must // instead be copied via ReflectionFactory.copyConstructor. private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) { checkInitted(); Constructor<T>[] res; // 调用 reflectionData(), 获取保存的信息,使用软引用保存,从而使内存不够可以回收 ReflectionData<T> rd = reflectionData(); if (rd != null) { res = publicOnly ? rd.publicConstructors : rd.declaredConstructors; // 存在缓存,则直接返回 if (res != null) return res; } // No cached value available; request value from VM if (isInterface()) { @SuppressWarnings("unchecked") Constructor<T>[] temporaryRes = (Constructor<T>[]) new Constructor<?>[0]; res = temporaryRes; } else { // 使用native方法从jvm获取构造器 res = getDeclaredConstructors0(publicOnly); } if (rd != null) { // 最后,将从jvm中读取的内容,存入缓存 if (publicOnly) { rd.publicConstructors = res; } else { rd.declaredConstructors = res; } } return res; } // Lazily create and cache ReflectionData 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 ReflectionData<T> newReflectionData(SoftReference<ReflectionData<T>> oldReflectionData, int classRedefinedCount) { if (!useCaches) return null; // 使用cas保证更新的线程安全性,所以反射是保证线程安全的 while (true) { ReflectionData<T> rd = new ReflectionData<>(classRedefinedCount); // try to CAS it... if (Atomic.casReflectionData(this, oldReflectionData, new SoftReference<>(rd))) { return rd; } // 先使用CAS更新,如果更新成功,则立即返回,否则测查当前已被其他线程更新的情况,如果和自己想要更新的状态一致,则也算是成功了 oldReflectionData = this.reflectionData; classRedefinedCount = this.classRedefinedCount; if (oldReflectionData != null && (rd = oldReflectionData.get()) != null && rd.redefinedCount == classRedefinedCount) { return rd; } } }复制代码6. 위와 같은 과정을 통해 생성자를 획득하게 되었습니다! 다음으로, 인스턴스를 반환하려면 해당 생성자의 newInstance()를 호출하기만 하면 됩니다!
// reflection data that might get invalidated when JVM TI RedefineClasses() is called 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; } }复制代码
관련 무료 학습 권장사항:
java basics위 내용은 JVM 반영 원리 기술 포인트에 대한 매우 상세한 요약~의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!