> Java> Java베이스> 본문

JVM 반영 원리 기술 포인트에 대한 매우 상세한 요약~

coldplay.xixi
풀어 주다: 2020-10-10 17:20:14
앞으로
2248명이 탐색했습니다.

오늘

Java Basics칼럼에서는 JVM 반영 원리 기술 사항에 대한 매우 자세한 요약을 소개합니다.

JVM 반영 원리 기술 포인트에 대한 매우 상세한 요약~

반사 정의

1. JAVA 반사 메커니즘은실행 상태

모든 클래스에 대해 이 클래스의 모든 속성과 메서드를 알 수 있습니다.

모든 개체에 대해 호출할 수 있습니다.

이러한 정보의 동적 획득과 객체 메서드를 동적으로 호출하는 기능을 Java 언어의 반사 메커니즘이라고 합니다.

리플렉션에서 제공하는 함수:

  • 런타임에 객체가 속한 클래스를 결정합니다.
  • 런타임에 모든 클래스의 객체를 구성합니다.
  • 런타임에 클래스의 멤버 변수와 메서드를 결정합니다.

(속성이 비공개인 경우 외부 세계는 일반적인 상황에서 속성 값을 조작하는 것이 허용되지 않습니다. 여기서 Field 클래스의 setAccessible(true) 메서드를 사용하여 일시적으로 속성을 열 수 있습니다. 연산 권한)

리플렉션의 사용 시나리오

  • Java로 코딩할 때 클래스와 객체의 구체적인 정보를 알고 있으면 이때 리플렉션 없이 클래스와 객체에 직접 연산을 할 수 있습니다
  • 모르는 경우. 코딩 시 클래스 또는 객체의 특정 정보를 보려면 Reflection을 사용하여

Reflection 소스 코드 분석

예제 API:

Class.forName("com.my.reflectTest").newInstance()复制代码
로그인 후 복사

1 Reflection을 사용하여 클래스 인스턴스 Class.forName("xxx");

을 얻으세요. 먼저, 클래스 정보를 얻기 위해 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); }复制代码
로그인 후 복사

3.newInstance()

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 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() { public Void run() { c.setAccessible(true); return null; } }); cachedConstructor = c; } catch (NoSuchMethodException e) { throw (InstantiationException) new InstantiationException(getName()).initCause(e); } } Constructor 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; } }复制代码
    로그인 후 복사
  • 4는 일치하는 생성자를 가져옵니다. ; 세 단계로 나뉩니다:

    1. 먼저 모든 생성자를 얻은 다음 매개변수 유형을 비교합니다. 2. 일치하는 항목을 찾은 후 ReflectionFactory를 통해 생성자의 복사본을 복사하고 반환합니다. 3. 그렇지 않으면 NoSuchMethodException;
  • private Constructor getConstructor0(Class[] parameterTypes, int which) throws NoSuchMethodException { // 获取所有构造器 Constructor[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC)); for (Constructor constructor : constructors) { if (arrayContentsEq(parameterTypes, constructor.getParameterTypes())) { return getReflectionFactory().copyConstructor(constructor); } } throw new NoSuchMethodException(getName() + "." + 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[] privateGetDeclaredConstructors(boolean publicOnly) { checkInitted(); Constructor[] res; // 调用 reflectionData(), 获取保存的信息,使用软引用保存,从而使内存不够可以回收 ReflectionData 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[] temporaryRes = (Constructor[]) 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 reflectionData() { SoftReference> reflectionData = this.reflectionData; int classRedefinedCount = this.classRedefinedCount; ReflectionData 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 newReflectionData(SoftReference> oldReflectionData, int classRedefinedCount) { if (!useCaches) return null; // 使用cas保证更新的线程安全性,所以反射是保证线程安全的 while (true) { ReflectionData 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 { volatile Field[] declaredFields; volatile Field[] publicFields; volatile Method[] declaredMethods; volatile Method[] publicMethods; volatile Constructor[] declaredConstructors; volatile Constructor[] 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:juejin.im
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!