¡Recomendar colección! Resumen súper detallado de los principios de reflexión y puntos técnicos de JVM

Definición de reflexión

1. El mecanismo de reflexión de JAVA está en funcionamiento.

Para cualquier clase, se pueden conocer todos los atributos y métodos de esta clase;

Para cualquier objeto, se puede llamar a cualquiera de sus métodos y propiedades;

La función de adquirir información dinámicamente y llamar dinámicamente a métodos de objetos se denomina mecanismo de reflexión del lenguaje Java.

Funciones proporcionadas por la reflexión:

  • Determinar la clase a la que pertenece cualquier objeto en tiempo de ejecución
  • Construye un objeto de cualquier clase en tiempo de ejecución
  • Juzgue las variables miembro y los métodos de cualquier clase en tiempo de ejecución
  • Llamar al método de cualquier objeto en tiempo de ejecución

    (Si el atributo es privado, el mundo exterior no puede manipular el valor del atributo en circunstancias normales, aquí puede usar el método setAccessible (verdadero) de la clase Field para abrir temporalmente la autoridad de operación)

Usa escenarios para la reflexión

  • Conozca la información específica de la clase y el objeto al codificar en Java. En este momento, puede manipular directamente la clase y el objeto sin reflexionar.
  • Si no conoce la información específica de la clase u objeto al codificar, debe usar la reflexión para lograr

Análisis de código fuente de reflexión

API de ejemplo: 

Class.forName("com.my.reflectTest").newInstance()

1. Reflexione para obtener la instancia de clase Class.forName ("xxx");

  Primero, llame al método estático de java.lang.Class para obtener la información de la clase.

Nota: forName () para obtener información de la clase por reflexión no deja la implementación a java, ¡sino a jvm para que la cargue!

          Lo principal es obtener el ClassLoader primero, luego llamar al método nativo para obtener la información, y la clase de carga es volver a llamar al parámetro ClassLoader para cargar la clase.

 @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() 其实相当于调用类的无参构造函数,主要做了三件事
  • La detección de permisos, si no se pasa, lanza una excepción directamente;

  • Busque el constructor sin parámetros y almacénelo en caché;

  • Llame al método de construcción sin parámetros del método específico, genere una instancia y regrese;
// 首先肯定是 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;
        }
    }

4. getConstructor0 () es obtener el constructor correspondiente; hay tres pasos:

  1. Obtenga todos los constructores primero y luego compare los tipos de parámetros;
  2. Después de encontrar una coincidencia, copie una copia del constructor a través de ReflectionFactory para regresar;
  3. De lo contrario, arroje 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));
    }

5. privateGetDeclaredConstructors (), los pasos principales para obtener todos los constructores;

  1. Primero intente obtenerlo del caché
  2. Si el caché no está disponible, vuelva a obtenerlo del jvm y guárdelo en el caché El caché se guarda con una referencia suave para asegurarse de que la memoria esté disponible;

// 获取当前类所有的构造方法,通过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 cla***edefinedCount = this.cla***edefinedCount;
        ReflectionData<T> rd;
        if (useCaches &&
            reflectionData != null &&
            (rd = reflectionData.get()) != null &&
            rd.redefinedCount == cla***edefinedCount) {
            return rd;
        }
        // else no SoftReference or cleared SoftReference or stale ReflectionData
        // -> create and replace new instance
        return newReflectionData(reflectionData, cla***edefinedCount);
    }

    // 新创建缓存,保存反射信息
    private ReflectionData<T> newReflectionData(SoftReference<ReflectionData<T>> oldReflectionData,
                                                int cla***edefinedCount) {
        if (!useCaches) return null;

        // 使用cas保证更新的线程安全性,所以反射是保证线程安全的
        while (true) {
            ReflectionData<T> rd = new ReflectionData<>(cla***edefinedCount);
            // try to CAS it...
            if (Atomic.casReflectionData(this, oldReflectionData, new SoftReference<>(rd))) {
                return rd;
            }
            // 先使用CAS更新,如果更新成功,则立即返回,否则测查当前已被其他线程更新的情况,如果和自己想要更新的状态一致,则也算是成功了
            oldReflectionData = this.reflectionData;
            cla***edefinedCount = this.cla***edefinedCount;
            if (oldReflectionData != null &&
                (rd = oldReflectionData.get()) != null &&
                rd.redefinedCount == cla***edefinedCount) {
                return rd;
            }
        }
    }

Además, use relactionData () para el almacenamiento en caché; ¡la estructura de datos de ReflectionData es la siguiente!

// 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 cla***edefinedCount when we created this ReflectionData instance
        final int redefinedCount;

        ReflectionData(int redefinedCount) {
            this.redefinedCount = redefinedCount;
        }
    }

6. A través de lo anterior, se obtiene el Constructor! Luego, simplemente llame a newInstance () de su constructor correspondiente para devolver la instancia.

// 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't inflate a constructor belonging to a vm-anonymous class
        // because that kind of class can't be referred to by name, hence can'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);
    }

Después de devolver la instancia del constructor, puede realizar la conversión de tipos de acuerdo con el exterior, de modo que pueda usar la interfaz o el método para llamar a la función de instancia.

para resumir

Bienvenido a prestar atención a la cuenta pública: un futuro brillante y recibir un resumen de las preguntas de la entrevista de Java de los principales fabricantes + una guía de aprendizaje para los puntos de conocimiento + un resumen de los puntos de conocimiento básicos de Java en un documento pdf de 300 páginas.
El contenido de estos materiales son todos los puntos de conocimiento que el entrevistador debe preguntar durante la entrevista. El capítulo incluye muchos puntos de conocimiento, incluidos conocimientos básicos, colecciones de Java, JVM, concurrencia multiproceso, principios de primavera, microservicios, Netty y RPC, Kafka , Diario, patrón de diseño, algoritmo Java, base de datos, Zookeeper, caché distribuida, estructura de datos, etc.

Supongo que te gusta

Origin blog.51cto.com/14801695/2540979
Recomendado
Clasificación