English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Подробное объяснение механизма загрузки JAVA классов (рекомендуется)

Компиляция JAVA-исходного кода состоит из трех процессов:

1. Механизм компиляции исходного кода.

2. Механизм загрузки класса

3. Механизм выполнения класса

Мы здесь основно рассказываем о двух механизмах: компиляции и загрузки класса.

Одна. Компиляция исходного кода

Компиляция кода выполняется компилятором JAVA. В основном это преобразование исходного кода в файл байт-кода (файл class). Формат файла байт-кода主要包括 две части: пул констант и байт-код методов.

Два. Загрузка класса

Жизненный цикл класса начинается с загрузки его в виртуальную память и заканчивается удалением из памяти. Процесс включает семь фаз, все фазы до инициализации относятся к части загрузки класса.

Загрузка----Валидация----Подготовка----Парсинг-----Инициализация----Использование-----Удаление

Система может загружать класс в первый раз при его использовании, или может использовать механизм предварительной загрузки для загрузки класса, при запуске java-программы запускается процесс java-виртуальной машины, два запуска java-программ происходят в двух разных процессах JVM, между двумя JVM данные не共享ятся.

1. Фаза загрузки

Этот процесс загрузки является одной из фаз механизма загрузки класса, эти два концепта не следует путать, в этой фазе необходимо выполнить следующие задачи:

1) Получается двоичный поток байтов класса по полному квалифицированному имени класса.

2) Преобразуется статическая структура хранения двоичного потока в runtime-структуру области методов.

3) В java-пуле создается объект Class, представляющий этот класс, в качестве входа для доступа к этим данным в области методов.

Из-за того, что в первом пункте не указано, откуда и как получить двоичный поток байтов класса, у разработчика есть много места для творчества в этой области. Об этом я расскажу позже в разделе о классовом загрузчике.

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);
 }
}

Результат выполнения:

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];
 }
}

Результат выполнения:

3. При использовании ссылки на константу не будет инициирован инициализация этого класса

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);
 }
}

Результат выполнения:

MIGU

При использовании final для определенного классового переменной, его значение уже определено в компиляции и поместлено в пул констант, поэтому при доступе к этой переменной равно напрямую получить из пула констант, не initializing этот класс.

Шаги инициализации

1. Если класс еще не загружен и не свяжен, программа сначала загружает этот класс и связывает его.

2. Если прямой родительский класс этого класса не загружен, сначала инициализируется его прямой родительский класс.

3. Если в классе есть инициализационные инструкции, система выполняет их по порядку.

Во втором шаге, если у прямого родительского класса又有 прямой родительский класс, система повторно повторит эти три шага для инициализации этого родительского класса, и так далее, JVM в первую очередь инициализирует класс java.lang.Object. При активном использовании любого класса системой гарантируется, что будет инициализирован этот класс и все его родительские классы.

Названное выше - это介绍JAVA загрузчик классов (рекомендуется) от редактора, который надеется помочь вам!

Объявление: содержание этой статьи предоставлено из Интернета, авторские права принадлежат соответствующему владельцу, контент был предложен и загружен пользователями Интернета, сайт не имеет права собственности, не underwent редактирование, и не несет ответственности за соответствующие юридические последствия. Если вы обнаружите содержимое,涉嫌侵犯版权, пожалуйста, отправьте письмо по адресу: notice#oldtoolbag.com (при отправке письма, пожалуйста, замените # на @) для сообщения о нарушении,并提供 соответствующие доказательства. При подтверждении, сайт немедленно удалят涉嫌侵权的内容.

Вам может понравиться