Heim > Java > JavaBase > Eine sehr detaillierte Zusammenfassung der technischen Punkte des JVM-Reflexionsprinzips ~

Eine sehr detaillierte Zusammenfassung der technischen Punkte des JVM-Reflexionsprinzips ~

coldplay.xixi
Freigeben: 2020-10-10 17:20:14
nach vorne
2353 Leute haben es durchsucht

In der heutigen Kolumne „Java-Grundlagen“ wird eine äußerst detaillierte Zusammenfassung der technischen Punkte des JVM-Reflexionsprinzips vorgestellt.

Reflexionsdefinition

1. Der JAVA-Reflexionsmechanismus befindet sich im

LaufzustandEine sehr detaillierte Zusammenfassung der technischen Punkte des JVM-Reflexionsprinzips ~

Für jede Klasse können Sie alle Eigenschaften und Methoden dieser Klasse kennen

Für jedes Objekt können Sie anrufen Alle seine Methoden und Eigenschaften; Diese dynamische Informationserfassung und die Funktion des dynamischen Aufrufs von Objektmethoden werden als Reflexionsmechanismus der Java-Sprache bezeichnet.

Durch Reflektion bereitgestellte Funktionen:

Bestimmen Sie die Klasse, zu der ein Objekt zur Laufzeit gehört.

Konstruieren Sie ein Objekt einer beliebigen Klasse zur Laufzeit.

Bestimmen Sie die Mitgliedsvariablen und Methoden einer beliebigen Klasse zur Laufzeit.
  • Rufen Sie die auf Methode eines beliebigen Objekts zur Laufzeit
  • (Wenn das Attribut privat ist, darf die Außenwelt den Attributwert unter normalen Umständen nicht bedienen. Hier können Sie die setAccessible(true)-Methode der Field-Klasse verwenden, um das vorübergehend zu öffnen Betriebsberechtigung)
  • Nutzungsszenarien der Reflexion

Sie kennen die spezifischen Informationen von Klassen und Objekten beim Codieren in Java. Zu diesem Zeitpunkt können Sie die Klassen und Objekte direkt ohne Reflexion bearbeiten

Wenn Sie es nicht wissen Um die spezifischen Informationen der Klasse oder des Objekts beim Codieren zu erhalten, sollten Sie Reflection verwenden, um eine

    Reflection-Quellcode-Analyse
  • Beispiel-API zu erreichen:
  • Class.forName("com.my.reflectTest").newInstance()复制代码
    Nach dem Login kopieren
  • 1. Reflection, um die Klasseninstanz Class.forName("xxx");

zu erhalten Rufen Sie zunächst die statische Methode von java.lang.Class auf, um Klasseninformationen abzurufen!

Hinweis: Die Reflexion von forName() zum Erhalten von Klasseninformationen überlässt die Implementierung nicht Java, sondern dem JVM zum Laden! L Holen Sie sich hauptsächlich zuerst den Classloader und rufen Sie dann die native Methode auf, um Informationen zu erhalten. Die Ladeklasse soll in den ClassLoader in die Klasse geladen werden!

 @CallerSensitive
    public static Class<?> forName(String className)
                throws ClassNotFoundException {
        // 先通过反射,获取调用进来的类信息,从而获取当前的 classLoader
        Class<?> caller = Reflection.getCallerClass();
        // 调用native方法进行获取class信息
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }复制代码
Nach dem Login kopieren

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);
    }复制代码
Nach dem Login kopieren

3. newInstance()

newInstance() 其实相当于调用类的无参构造函数,主要做了三件事复制代码
Nach dem Login kopieren

Berechtigungserkennung, wenn sie nicht erfolgreich ist, wird direkt eine Ausnahme ausgelöst;

Suchen Sie den Konstruktor ohne Argumente und speichern Sie ihn im Cache.

  • Rufen Sie den Konstruktor ohne Argumente der jeweiligen Methode auf, generieren Sie eine Instanz und geben Sie sie zurück.

  • // 首先肯定是 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&#39;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;
            }
        }复制代码
    Nach dem Login kopieren
  • 4 ; in drei Schritte unterteilt:

    1. Zuerst alle Konstruktoren abrufen und dann die Parametertypen vergleichen; 2. Nachdem Sie eine Übereinstimmung gefunden haben, kopieren Sie eine Kopie des Konstruktors über ReflectionFactory und geben Sie sie zurück. 3. Andernfalls werfen Sie NoSuchMethodException;
  • 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));
        }复制代码
    Nach dem Login kopieren
  • 5. privateGetDeclaredConstructors(), rufen Sie alle Hauptschritte des Konstruktors ab;

     1. Versuchen Sie zuerst, es aus dem Cache abzurufen; 2. Wenn der Cache nicht vorhanden ist, rufen Sie ihn vom JVM ab und speichern Sie ihn im Cache. Der Cache verwendet Soft-Referenzen, um sicherzustellen, dass der Speicher verfügbar ist.
  • // 获取当前类所有的构造方法,通过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;
                }
            }
        }复制代码
    Nach dem Login kopieren
Verwenden Sie außerdem relactionData() zum Cache-Speichern ; Die Datenstruktur von ReflectionData ist wie folgt!

// 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;
        }
    }复制代码
Nach dem Login kopieren

6. Dadurch haben Sie den Konstruktor erhalten! Als nächstes müssen Sie nur noch newInstance() des entsprechenden Konstruktors aufrufen, um die Instanz zurückzugeben!

// return tmpConstructor.newInstance((Object[])null); 
    // java.lang.reflect.Constructor
    @CallerSensitive
    public T newInstance(Object ... initargs)
        throws InstantiationException, IllegalAccessException,
               IllegalArgumentException, InvocationTargetException
    {
        if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                Class<?> caller = Reflection.getCallerClass();
                checkAccess(caller, clazz, null, modifiers);
            }
        }
        if ((clazz.getModifiers() & Modifier.ENUM) != 0)
            throw new IllegalArgumentException("Cannot reflectively create enum objects");
        ConstructorAccessor ca = constructorAccessor;   // read volatile
        if (ca == null) {
            ca = acquireConstructorAccessor();
        }
        @SuppressWarnings("unchecked")
        T inst = (T) ca.newInstance(initargs);
        return inst;
    }
    // sun.reflect.DelegatingConstructorAccessorImpl
    public Object newInstance(Object[] args)
      throws InstantiationException,
             IllegalArgumentException,
             InvocationTargetException
    {
        return delegate.newInstance(args);
    }
    // sun.reflect.NativeConstructorAccessorImpl
    public Object newInstance(Object[] args)
        throws InstantiationException,
               IllegalArgumentException,
               InvocationTargetException
    {
        // We can&#39;t inflate a constructor belonging to a vm-anonymous class
        // because that kind of class can&#39;t be referred to by name, hence can&#39;t
        // be found from the generated bytecode.
        if (++numInvocations > ReflectionFactory.inflationThreshold()
                && !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) {
            ConstructorAccessorImpl acc = (ConstructorAccessorImpl)
                new MethodAccessorGenerator().
                    generateConstructor(c.getDeclaringClass(),
                                        c.getParameterTypes(),
                                        c.getExceptionTypes(),
                                        c.getModifiers());
            parent.setDelegate(acc);
        }
 
        // 调用native方法,进行调用 constructor
        return newInstance0(c, args);
    }复制代码
Nach dem Login kopieren
Nachdem Sie die Instanz des Konstruktors zurückgegeben haben, können Sie eine Typkonvertierung basierend auf der externen Umgebung durchführen und dann die Schnittstelle oder Methode verwenden, um die Instanzfunktion aufzurufen.

Verwandte kostenlose Lernempfehlungen:

Java-Grundlagen

Das obige ist der detaillierte Inhalt vonEine sehr detaillierte Zusammenfassung der technischen Punkte des JVM-Reflexionsprinzips ~. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:juejin.im
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage