[Java] Carga de clases Java y cargador de clases

prefacio

La fase de carga de clases de Java se divide en: carga, enlace e inicialización, y el proceso de enlace incluye: verificación, preparación y resolución.

1. Cargando

Cargue el código de bytes de la clase en el área del método y use internamente la clase de instancia de C++ para describir la clase de Java.

Campos importantes de instanceKclass:

  • _java_mirror: espejo de clase Java, que almacena la dirección del objeto de clase, por ejemplo, para String, almacena String.class
  • _super: la clase padre
  • _métodos: el método
  • _constants: el grupo de constantes
  • _class_loader: cargador de clases
  • _vtable: tabla de métodos virtuales
  • _itable: tabla de métodos de interfaz

inserte la descripción de la imagen aquí

2. Enlaces

La fase de vinculación consta de 验证、准备、初始化tres partes.

verificar

Verifique que la clase cumpla con la especificación JVM y realice controles de seguridad, por ejemplo: verifique el número mágico del archivo Java

Preparar

Asignar espacio de direcciones para variables estáticas, establecer valores predeterminados

  • La asignación y asignación de variables estáticas son dos pasos, la asignación de espacio se completa en la fase de preparación y la asignación se completa en la fase de inicialización;
  • Si la variable estática es de tipo final y el tipo de variable es un tipo de datos básico o un objeto de cadena, se asigna en la fase de preparación;
  • Si la variable estática es de tipo final y el tipo de variable es un objeto de referencia, todavía se asigna en la fase de inicialización;

analizar

resuelve las referencias simbólicas en el grupo constante para referencias directas

3. Inicialización

Inicialice call ()v, es decir, ejecute el constructor de la clase, bloques de código, etc., y la máquina virtual garantiza la seguridad de subprocesos de esta clase

momento

En pocas palabras, la inicialización de clase es perezosa

  • La clase donde se encuentra el método principal siempre se inicializará primero;
  • La primera vez que acceda a la variable estática o método estático de la clase, debido a que estas variables no son definitivas, serán asignadas durante la fase de inicialización de la clase;
  • La inicialización de la subclase provocará la inicialización de la clase principal;
  • La variable estática de la clase principal del método de la subclase provocará la inicialización de la clase principal;
  • Clase.forName;
  • inicialización de nuevas causas;

no desencadena la inicialización de la clase

  • Las variables estáticas finales estáticas (tipos básicos y cadenas) de la clase de acceso no serán inicializadas, debido a que la asignación de estas variables está en etapa de preparación;
  • class object.class no desencadena la inicialización de la clase;
  • La creación de una matriz de esta clase no activa la inicialización;
  • El método loadClass del cargador de clases;
  • Cuando el parámetro 2 de Class.forName es falso

4. Cargador de clases

Tome JDK8 como ejemplo

nombre Dónde cargar las clases ilustrar
Cargador de clases Bootstrap JAVA_HOME/jre/lib sin acceso directo
Extensión ClassLoader JAVA_HOME/jre/lib/ext Superior es Bootstrap ClassLoader, el acceso es nulo
Cargador de clases de aplicaciones ruta de clase El superior es Extensión ClassLoader
cargador de clases personalizado padre personalizado 为 Cargador de clases de aplicaciones

El papel del cargador de clases: cargar el bytecode binario de la clase

Delegación de Padres

El modo de delegación padre es un mecanismo de carga de clases Java, que define una relación padre-hijo jerárquica, y el cargador de clases padre delega las solicitudes hacia abajo hasta que se encuentra un cargador de clases adecuado.

  • Primero, verificará el caché para averiguar si el cargador ya ha cargado esta clase y, si no, irá al cargador de clases principal para encontrarlo;
  • Si no se encuentra en la memoria caché, el cargador de clases se utilizará de arriba a abajo para crear la clase;
  • Finalmente regrese a esta clase;
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 {
                        // 向 Bootstrap 类加载器中找
                        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();
                    // 调用 findClass 去创建类
                    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;
        }
    }

Supongo que te gusta

Origin blog.csdn.net/u011397981/article/details/130426900
Recomendado
Clasificación