Directorio de artículos
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
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;
}
}