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

JAVA 클래스 로드 메커니즘 자세히 설명(추천)

JAVA 소스 코드 컴파일은 세 단계로 구성됩니다:

1、소스 코드 컴파일 메커니즘

2、클래스 로드 메커니즘

3、클래스 실행 메커니즘

우리는 여기서 컴파일과 클래스 로드这两种 메커니즘을 주로 설명합니다.

1. 소스 코드 컴파일

JAVA 소스 코드 컴파일은 JAVA 소스 코드 컴파일러로 완료됩니다. 주로 소스 코드를 바이너리 코드 파일(class 파일)로 컴파일합니다. 바이너리 코드 파일의 형식은 주로 두 부분으로 나뉩니다: 상수 풀과 메서드 바이너리 코드.

2. 클래스 로드

클래스의 생명주기는 가상 머신 메모리에 로드된 시점에서 시작하여 메모리에서 언로드된 시점까지입니다. 이 과정은 일곱 단계로 구성되며, 초기화 이전의 모든 단계는 클래스 로드 부분에 속합니다.

로드----검증----준비----파싱-----이니셜라이제이션----사용-----언로드

시스템은 첫 번째로 사용하는 특정 클래스를 로드할 수 있으며, 특정 클래스를 로드하기 위해 사전 로드 메커니즘을 사용할 수도 있습니다. 특정 java 프로그램을 실행할 때, java 가상 머신 프로세스가 시작되며, 두 번째로 실행되는 java 프로그램은 두 개의 다른 JVM 프로세스에 있으며, 두 JVM 간에는 데이터가 공유되지 않습니다.

1로드 단계

이 프로세스에서의 로드는 클래스 로드 메커니즘의 단계 중 하나입니다. 이 두 개념을 혼동하지 마세요. 이 단계에서 완료해야 할 작업은 다음과 같습니다:

1이 클래스의 전체 이름을 통해 이 클래스를 정의하는 바이너리 바이트 스트림을 얻습니다.

2이 바이너리 스트림을 대표하는 정적 저장 구조를 메서드 영역의 실행 시 데이터 구조로 변환합니다.

3java 힙에서 이 클래스를 대표하는 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로修饰된 클래스 변수의 값은 컴파일 시에 이미 결정되어 정적 풀에 저장되므로, 클래스 변수에 접근할 때, 정적 풀에서 직접 가져오는 것이며, 해당 클래스를 초기화하지 않습니다.

초기화 단계

1클래스가 로드되지 않았거나 연결되지 않았다면, 프로그램은 먼저 해당 클래스를 로드하고 연결합니다.

2클래스의 직접 부모 클래스가 로드되지 않았다면, 먼저 그 직접 부모 클래스를 초기화합니다.

3클래스에 초기화 문장이 있으면, 시스템은 이러한 초기화 문장을 차례대로 실행합니다.

두 번째 단계에서, 직접 부모 클래스가 또 다른 직접 부모 클래스를 가지고 있다면, 시스템은 이 세 단계를 다시 반복하여 이 부모 클래스를 초기화합니다. 이를 계속 반복하여 JVM은 항상 java.lang.Object 클래스를 먼저 초기화합니다. 프로그램이 어떤 클래스든 사용할 때, 시스템은 이 클래스와 모든 부모 클래스가 초기화되도록 보장합니다.

위에서 소개한 JAVA 클래스 로드 메커니즘(추천)은 여러분들에게 도움이 되길 바랍니다!

언급: 이 문서의 내용은 인터넷에서 가져왔으며, 저작권자는 모두 소유합니다. 내용은 인터넷 사용자가 자발적으로 기여하고 업로드한 것이며, 이 사이트는 소유권을 가지지 않으며, 인공 편집을 하지 않았으며, 관련 법적 책임도 부담하지 않습니다. 저작권 위반 내용이 있을 경우, 이메일을 notice#w로 보내 주세요.3codebox.com에 이메일을 보내면 (#을 @으로 변경해야 합니다.) 신고하고 관련 증거를 제공해 주세요. 사실이 확인되면, 이 사이트는 즉시 위반 내용을 제거합니다.

당신이 좋아할 만한 것