English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
La compilación de código fuente de Java consta de tres procesos:
1、mecanismo de compilación de código fuente.
2、mecanismo de carga de clases
3、mecanismo de ejecución de clases
Aquí, nos centraremos en dos mecanismos: la compilación y la carga de clases.
I. Compilación de código fuente
La compilación de código es realizada por el compilador de código fuente de Java. Principalmente, convierte el código fuente en archivos de código de bytes (archivos class). El formato del archivo de código de bytes se divide principalmente en dos partes: la piscina de constantes y el código de bytes de métodos.
II. Carga de clases
La vida útil de una clase comienza cuando se carga en la memoria del entorno virtual y termina cuando se desecha de la memoria. El proceso consta de siete etapas, y todas las etapas antes de la inicialización pertenecen a la parte de carga de la clase.
Carga----Verificación----Preparación----Análisis-----Inicialización----Uso-----Desconexión
El sistema puede cargar una clase por primera vez cuando se utiliza alguna clase, o puede usar un mecanismo de pre-carga para cargar una clase. Al ejecutar un programa Java, se inicia un proceso de máquina virtual Java, y los dos programas Java ejecutados dos veces están en dos procesos de JVM diferentes. No compartirán datos entre sí.
1、fase de carga
La carga en este proceso es una etapa del mecanismo de carga de clases, y estos dos conceptos no deben confundirse. En esta etapa, se deben completar las siguientes tareas:
1Se obtiene el flujo de bytes binario definido para esta clase mediante el nombre completo de la clase.
2Se convierte la estructura de almacenamiento estático representada por este flujo de bytes en la estructura de datos de tiempo de ejecución de la zona de métodos.
3Se genera un objeto Class que representa esta clase en el heap de Java, que actúa como punto de entrada para acceder a estos datos en la zona de métodos.
Debido a que el primer punto no especifica desde dónde y cómo obtener el flujo de bytes binario de la clase, este área deja mucho espacio para que los desarrolladores se expresen. Esto lo explicaré en el cargador de clases más adelante.
2、准备阶段
这个阶段正式为类变量(被static修饰的变量)分配内存并设置类变量初始值,这个内存分配是发生在方法区中。
1、注意这里并没有对实例变量进行内存分配,实例变量将会在对象实例化时随着对象一起分配在JAVA堆中。
2、这里设置的初始值,通常是指数据类型的零值。
private static int a = 3;
这个类变量a在准备阶段后的值是0,将3赋值给变量a是发生在初始化阶段。
3、初始化阶段
初始化是类加载机制的最后一步,这个时候才正真开始执行类中定义的JAVA程序代码。在前面准备阶段,类变量已经赋过一次系统要求的初始值,在初始化阶段最重要的事情就是对类变量进行初始化,关注的重点是父子类之间各类资源初始化的顺序。
java类中对类变量指定初始值有两种方式:1、声明类变量时指定初始值;2、使用静态初始化块为类变量指定初始值。
初始化的时机
1)创建类实例的时候,分别有:1、使用new关键字创建实例;2、通过反射创建实例;3、通过反序列化方式创建实例。
new Test(); Class.forName("com.mengdd.Test");
2)调用某个类的类方法(静态方法)
Test.doSomething();
3)访问某个类或接口的类变量,或为该类变量赋值。
int b=Test.a; Test.a=b;
4)初始化某个类的子类。当初始化子类的时候,该子类的所有父类都会被初始化。
5)直接使用java.exe命令来运行某个主类。
除了上面几种方式会自动初始化一个类,其他访问类的方式都称不会触发类的初始化,称为被动引用。
1、子类引用父类的静态变量,不会导致子类初始化。
public class SupClass { public static int a = 123; static { System.out.println("supclass init"); } } public class SubClass extends SupClass { static { System.out.println("subclass init"); } } public class Test { public static void main(String[] args) { System.out.println(SubClass.a); } }
Resultados de la ejecución:
supclass init
123
2、通过数组定义引用类,不会触发此类的初始化
public class SupClass { public static int a = 123; static { System.out.println("supclass init"); } } public class Test { public static void main(String[] args) { SupClass[] spc = new SupClass[10]; } }
Resultados de la ejecución:
3、Al citar una constante, no se desencadena la inicialización de la clase
public class ConstClass { public static final String A= "MIGU"; static { System.out.println("ConstCLass init"); } } public class TestMain { public static void main(String[] args) { System.out.println(ConstClass.A); } }
Resultados de la ejecución:
MIGU
Cuando se utiliza final para modificar una variable de clase, su valor ya está determinado en tiempo de compilación y colocado en la piscina de constantes, por lo que al acceder a la variable de clase, es equivalente a obtener directamente de la piscina de constantes, sin inicializar la clase.
Pasos de inicialización
1、Si la clase no se ha cargado y conectado, el programa primero cargará y conectará la clase.
2、Si la clase padre directa no se ha cargado, se inicializará primero su clase padre directa.
3、Si la clase tiene instrucciones de inicialización, el sistema ejecutará estas instrucciones de inicialización sucesivamente.
En la segunda etapa, si el padre directo tiene otro padre directo, el sistema repetirá estos tres pasos para inicializar este padre directo, y así sucesivamente, JVM siempre inicializa primero la clase java.lang.Object. Cuando el programa utiliza cualquier clase activamente, el sistema garantiza que se inicializará esa clase y todas sus clases padre.
Lo mencionado anteriormente es el mecanismo de carga de clases JAVA que el editor le ha presentado (recomendado), esperamos que sea útil para usted!
Aviso: Este artículo se comparte en línea, el contenido pertenece al autor original, el sitio web no posee los derechos de autor, no ha sido editado por humanos y no asume ninguna responsabilidad legal. Si encuentra contenido con derechos de autor, por favor envíe un correo electrónico a: notice#w3Declaración: El contenido de este artículo se obtiene de la red, el derecho de autor pertenece al propietario original, el contenido se contribuye y carga espontáneamente por los usuarios de Internet, este sitio web no posee los derechos de propiedad, no se ha procesado editorialmente y no asume ninguna responsabilidad legal. Si encuentra contenido sospechoso de infracción de derechos de autor, le invitamos a enviar un correo electrónico a: notice#w