English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
La compilazione del codice sorgente Java è composta da tre fasi:
1、Mecanismo di compilazione del codice sorgente.
2、Mecanismo di caricamento delle classi
3、Mecanismo di esecuzione delle classi
Qui, ci concentriamo principalmente sulla compilazione e sul meccanismo di caricamento delle classi.
Primo, compilazione del codice sorgente
La compilazione del codice è completata dal compilatore di codice sorgente Java. Principalmente, compila il codice sorgente in file di bytecode (file class). Il formato del file bytecode è principalmente diviso in due parti: pool di costanti e bytecode di metodo.
Secondo, caricamento delle classi
Il ciclo di vita della classe inizia quando viene caricata nella memoria del JVM e termina quando viene scaricata dalla memoria. Il processo ha sette fasi, e tutte le fasi prima dell'inizializzazione appartengono alla parte di caricamento della classe
Caricamento----Verifica----Preparazione----Parsaggio-----Inizializzazione----Uso-----Dismissione
Il sistema potrebbe caricare una classe la prima volta che viene utilizzata, o potrebbe utilizzare un meccanismo di pre-caricamento per caricare una classe. Quando si avvia un programma Java, viene avviato un processo di JVM, due programmi Java eseguiti due volte si trovano in due processi JVM diversi, e due JVM non condividono dati.
1、Fase di caricamento
Questo processo di caricamento è una fase del meccanismo di caricamento delle classi, non mescolare questi due concetti. Le cose da completare in questa fase sono:
1) Ottieni il flusso binario in byte che definisce una classe tramite il nome qualificato della classe.
2) Converti la struttura di archiviazione statica rappresentata da questo flusso di byte in una struttura di dati di runtime della sezione di metodo.
3) Genera un oggetto Class che rappresenta questa classe nel heap di Java, come punto di ingresso per accedere a questi dati nella sezione di metodo.
Poiché il primo punto non specifica da dove ottenere e come ottenere il flusso binario in byte della classe, questa area lascia molto spazio per i sviluppatori. Questo lo spiegherò in dettaglio nel caricatore di classi successivo.
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); } }
Risultato dell'esecuzione:
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]; } }
Risultato dell'esecuzione:
3、Quando si fa riferimento a una costante, non si inizializza la classe corrente
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); } }
Risultato dell'esecuzione:
MIGU
Quando si utilizza final per修饰 una variabile di classe, il suo valore è già determinato e messo nel pool delle costanti durante la compilazione, quindi quando si accede a questa variabile di classe, è come ottenere direttamente dal pool delle costanti, senza inizializzare la classe.
Passaggi di inizializzazione
1、Se la classe non è stata caricata e collegata, il programma carica prima la classe e la collega.
2、Se il padre diretto della classe non è stato caricato, inizializza prima il padre diretto.
3、Se la classe contiene istruzioni di inizializzazione, il sistema esegue queste istruzioni di inizializzazione in successione.
Nel secondo passaggio, se il padre diretto ha anche un padre diretto, il sistema eseguirà nuovamente questi tre passaggi per inizializzare questo padre, e così via, JVM inizializzerà sempre prima la classe java.lang.Object. Quando il programma utilizza qualsiasi classe attivamente, il sistema garantisce che la classe e tutte le classi dei genitori vengano inizializzate.
Come sopra descritto, l'editor ha introdotto il meccanismo di caricamento delle classi JAVA (raccomandato) e spera che sia utile a tutti voi!
Dichiarazione: il contenuto di questo articolo è stato prelevato da Internet, i diritti d'autore appartengono agli autori originali, il contenuto è stato contribuito e caricato autonomamente dagli utenti di Internet, questo sito non detiene i diritti di proprietà, non è stato editato manualmente e non assume alcuna responsabilità legale correlata. Se trovi contenuti sospetti di violazione del copyright, ti preghiamo di inviare una e-mail a notice#oldtoolbag.com (sostituisci # con @ durante l'invio dell'e-mail) per segnalare il problema e fornire prove pertinenti. Una volta verificata, questo sito rimuoverà immediatamente il contenuto sospetto di violazione del copyright.