предисловие
При каких обстоятельствах будет запущена загрузка класса? В этой статье мы обсудим несколько ситуаций в сочетании с демонстрацией кода в надежде помочь всем.
время загрузки класса
В какой ситуации должен начаться первый этап процесса загрузки класса: загрузка? В спецификации виртуальной машины Java нет обязательных ограничений, которые можно оставить на усмотрение конкретной реализации виртуальной машины. Однако для этапа инициализации спецификация виртуальной машины строго оговаривает, что класс должен быть инициализирован немедленно в следующих ситуациях: Если класс не был инициализирован, его инициализацию необходимо инициировать в первую очередь.
Создайте экземпляр класса
Чтобы проверить загрузку класса, мы сначала настраиваем параметр JVM.
-XX:+TraceClassLoading 监控类的加载
Конфигурация IDE выглядит следующим образом:
демо-код:
public class ClassLoadInstance {
static {
System.out.println("ClassLoadInstance类初始化时就会被执行!");
}
public ClassLoadInstance() {
System.out.println("ClassLoadInstance构造函数!");
}
}
public class ClassLoadTest {
public static void main(String[] args) {
ClassLoadInstance instance = new ClassLoadInstance();
}
}
результат операции:
в заключении:
При создании нового экземпляра ClassLoadInstance обнаруживается, что ClassLoadInstance был загружен, поэтому создается новый объект экземпляра, который инициирует загрузку класса.
Доступ к статическим переменным класса
демо-код:
public class ClassLoadStaticVariable {
static {
System.out.println("ClassLoadStaticVariable类初始化时就会被执行!");
}
public static int i = 100;
public ClassLoadStaticVariable() {
System.out.println("ClassLoadStaticVariable构造函数!");
}
}
public class ClassLoadTest {
public static void main(String[] args) {
System.out.println(ClassLoadStaticVariable.i);
}
}
результат операции:
в заключении:
При доступе к статической переменной i класса ClassLoadStaticVariable класс ClassLoadStaticVariable оказывается загруженным, поэтому статическая переменная класса Access инициирует загрузку класса.
Уведомление:
При доступе к статическим переменным final-modified загрузка класса не будет запущена, поскольку эта константа была помещена в пул констант во время компиляции.
Доступ к статическим методам класса
демо-код:
public class ClassLoadStaticMethod {
static {
System.out.println("ClassLoadStaticMethod类初始化时就会被执行!");
}
public static void method(){
System.out.println("静态方法被调用");
}
public ClassLoadStaticMethod() {
System.out.println("ClassLoadStaticMethod构造函数!");
}
}
public class ClassLoadTest {
public static void main(String[] args) {
ClassLoadStaticMethod.method();
}
}
результат операции:
в заключении:
При доступе к статическому методу метода метода класса ClassLoadStaticMethod, обнаружено, что класс класса ClassLoadSTaticMethod загружен, поэтому доступ к статическому методу класса запускает загрузку класса.
отражение
демо-код:
package classload;
public class ClassLoadStaticReflect {
static {
System.out.println("ClassLoadStaticReflect类初始化时就会被执行!");
}
public static void method(){
System.out.println("静态方法被调用");
}
public ClassLoadStaticReflect() {
System.out.println("ClassLoadStaticReflect构造函数!");
}
}
public class ClassLoadTest {
public static void main(String[] args) throws ClassNotFoundException {
Class.forName("classload.ClassLoadStaticReflect");
}
}
результат операции:
в заключении:
Когда класс ClassLoadStaticReflect получен путем отражения, обнаруживается, что класс ClassLoadStaticReflect загружен, поэтому отражение инициирует загрузку класса.
Когда класс инициализируется и обнаруживается, что его родительский класс не был инициализирован, сначала запускается инициализация родительского класса.
демо-код:
//父类
public class ClassLoadSuper {
static {
System.out.println("ClassLoadSuper类初始化时就会被执行!这是父类");
}
public static int superNum = 100;
public ClassLoadSuper() {
System.out.println("父类ClassLoadSuper构造函数!");
}
}
//子类
public class ClassLoadSub extends ClassLoadSuper {
static {
System.out.println("ClassLoadSub类初始化时就会被执行!这是子类");
}
public static int subNum = 100;
public ClassLoadSub() {
System.out.println("子类ClassLoadSub构造函数!");
}
}
public class ClassLoadTest {
public static void main(String[] args) throws ClassNotFoundException {
ClassLoadSub classLoadSub = new ClassLoadSub();
}
}
результат операции:
в заключении:
При создании экземпляра подкласса ClassLoadSub обнаруживается, что родительский класс ClassLoadSuper загружается первым, поэтому при инициализации класса обнаруживается, что его родительский класс не был инициализирован, и сначала запускается инициализация родительского класса.
При запуске виртуальной машины сначала инициализируется класс, определяющий метод main().
демо-код:
package classload;
public class ClassLoadTest {
public static void main(String[] args) {
System.out.println(ClassLoadSub.subNum);
}
}
результат операции:
в заключении:
При запуске виртуальной машины, даже если загружены такие классы, как ClassLoadSub, ClassLoadSuper и ClassLoadTest, ClassLoadTest загружается первым, то есть класс, определяющий метод main(), инициирует загрузку класса первым.
Упражнения и резюме
Мы закончили анализ шести основных моментов запуска загрузки класса. Вы чувствуете себя неудовлетворенными без вопросов? Далее давайте проанализируем классический вопрос интервью о загрузке классов.
class SingleTon {
private static SingleTon singleTon = new SingleTon();
public static int count1;
public static int count2 = 0;
private SingleTon() {
count1++;
count2++;
}
public static SingleTon getInstance() {
return singleTon;
}
}
public class ClassLoadTest {
public static void main(String[] args) {
SingleTon singleTon = SingleTon.getInstance();
System.out.println("count1=" + singleTon.count1);
System.out.println("count2=" + singleTon.count2);
}
}
результат операции:
анализировать:
- SingleTon.getInstance(), вызвать статический метод, запустить загрузку класса SingleTon.
- Инициализация загрузки класса SingleTon, которая инициализирует статические переменные по порядку.
- Сначала выполните private static SingleTon singleTon = new SingleTon(); После вызова конструктора count1 и count2 равны 1;
- Выполнить по порядку public static int count1, присваивания нет, поэтому count1 по-прежнему равен 1;
- Выполнить в порядке public static int count2 = 0, поэтому count2 становится равным 0.
Личный публичный аккаунт
Приглашаем всех обратить внимание, учиться и обсуждать вместе.