Notes
  • Introduce
  • Go
    • Grammar
      • Basic
      • Goroutines & Channels
      • Test
    • System Library
      • Module
      • sync
      • context
      • net
    • Concurrency in Go
    • The Go Memory Model
    • Code Snippet
  • Rust
    • The Rust Programming Language
    • Rust by Example
  • JAVA
    • Preface
    • Grammar
      • Basic
      • Data Types
      • Operator
      • Exceptions
    • Class Libraries
      • Collection
      • Stream
      • IO
      • NIO
      • RMI
    • Concurrency
      • Preface
      • JMM
      • Synchronized & CAS
      • Deadlock
      • Thread
      • Lock & Condition
      • Utility Class
      • Thread-safe Collection
      • Atomic Class
      • Fork/Join
      • Concurrency Design Patterns
        • Immutable
        • Copy-on-Write
        • ThreadLocal
        • Multitheading If
        • Division
    • JVM
      • Class & Instance Initialization
      • Runtime Data Area
      • Garbage Collection
    • Web Container
      • Tomcat Architecture
      • Jetty Architecture
    • Spring
    • Tuning
      • Programming
  • Computer Science
    • Computer Organization
    • Algorithm
      • Complexity
      • Linear List
      • Sort
      • Binary Search
      • Skip List
      • Hash Table
      • Tree
      • Graph
      • String Matching
      • Bloom Filter
      • Greedy Algorithm
      • Divide and Conquer
      • Back Tracking
      • Dynamic Programming
    • Network Protocol
      • Pysical Layer
      • Data Link Layer
      • Network Layer
      • Transport Layer
      • Application layer
      • HTTP
      • HTTP/2 in Action
    • Operating System
      • Basic
      • System Initialization
      • Diagnostic Tools
      • CPU Diagnosis
      • Memory Diagnosis
      • Disk Diagnosis
      • Network Diagnosis
      • Monitor System
    • Design Patterns
      • UML
      • OOP
      • Principle
      • Refactoring & Specification
      • Creational
        • Singleton
        • Factory
        • Builder
        • Prototype
      • Structural
        • Proxy
        • Bridge
        • Decorator
        • Adapter
        • Facade
        • Composite
        • FlyWeight
      • Behavioral
        • Observer
        • Template Method
        • Strategy
        • State
        • Iterator
        • Chain of Responsibility
    • Distributed System
      • Protocol & Algorithm
      • Transcation
      • Theory
      • Resource Management
      • Scheduling
      • Computing
      • Message Queue
      • Cache
      • Consistent Hashing
  • database
    • InfluxDB
      • In-Memory Index
      • Meta
    • MySQL
      • SQL
      • Architecture
      • Log
      • Transaction
      • Indexing
      • Lock
      • Storage
    • Redis
    • Elasticsearch
      • Local Debug
    • HBase
    • Kafka
    • ZooKeeper
  • Reading
    • RocketMQ
    • 演说之禅
    • So Good They Can't Ignore You
    • 学会提问
    • Lecture
  • Other
    • v2ray
    • Kubernetes
    • Git
    • Maven
    • Anaconda And Conda
    • Fuck! Shit!
      • Remove Final by Reflection
      • Ingress Host
      • ExecuterService submit
  • Open source contribution
Powered by GitBook
On this page
  • 类加载过程
  • 加载(Loading)
  • 连接(Linking)
  • 初始化(Initialization)
  • 实例初始化
  • 案例
  • 类加载与实例加载顺序
  • 常量引用
  • 父类静态变量引用
  • 数组引用

Was this helpful?

  1. JAVA
  2. JVM

Class & Instance Initialization

PreviousJVMNextRuntime Data Area

Last updated 6 years ago

Was this helpful?

类加载过程

加载(Loading)

  1. 通过全类名获取定义此类的二进制字节流。

  2. 将字节流所代表的静态存储结构转换为方法区的运行时数据结构。

  3. 在内存中生成一个代表该类的 Class 对象,作为方法区这些数据的访问入口。

连接(Linking)

加载阶段和连接阶段的部分内容是交叉进行的,加载阶段尚未结束,连接阶段可能就已经开始了。

验证(Verification)

确保 Class 文件字节流中的信息符合虚拟机的要求,并且不会危害虚拟机自身的安全。

  • 文件格式验证:是否以魔数开头、版本号是否能被当前虚拟机处理等。

  • 元数据验证:语义分析,是否有父类、父类是否可以被继承、是否为抽象类等。

  • 字节码验证:最复杂的阶段,字节码指令不会跳转到方法体以外等。

  • 符号引用验证:将符号引用转化为直接引用,这个转换发生再解析阶段,此验证确保解析能够正常执行。

准备(Preparing)

准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中分配。

  • 仅包括类变量,被 static 修饰,不包括实例变量。

  • 若被 static final 修饰(常量),则会在准备阶段直接赋值为代码中定义的值。

解析(Resolution)

虚拟机将常量池内的符号引用替换为直接引用的过程。主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用限定符7类符号引用进行。

  • 符号引用(Symbolic References):一组符号描述所引用的目标,任何形式的字面量,只需能无歧义地定位到目标。与内存布局无关。

  • 直接引用(Direct References):直接指向目标的指针、相对偏移量、间接定位到目标的句柄等。与内存布局有关。

初始化(Initialization)

类的加载时机虚拟机并没有规定,但是规定以下情况必须对类进行初始化:

  1. 遇到new、getstatic、putstatic、invokestatic 这四条字节码指令时。即 new 一个对象、读取类的静态变量(若静态变量被 final 修饰、在编译期把结果放入常量池除外)、设置类的静态变量、调用类的静态方法(包括 main 方法)。

  2. 使用 java.lang.reflect 对类进行反射调用时。

  3. 一个子类的初始化需要先初始化父类。

  4. 当使用动态动态语言时,如果一个 MethodHandle 实例的最后解析结构为 REF_getStatic、REF_putStatic、REF_invokeStatic、的方法句柄,并且这个句柄没有初始化,则需要先触发器初始化。

类的初始化即调用<clinit>()方法,带锁,线程安全。仅执行一次。<clinit>()组成:

  • 静态变量的显示赋值。

  • 静态代码块。

注意: 静态变量的显示赋值和静态代码块按照书写顺序执行。

实例初始化

  1. 实例初始化就是执行<init>()方法。

  2. <init>()可能有多个,有几个构造函数就有几个。

  3. <init>()方法组成:

    • super(),一定是第一行。

    • 非静态变量显示赋值代码。

    • 非静态代码块。

    • 构造方法代码,一定是最后。

    注意: 非静态变量显示赋值代码和非静态代码块按照书写顺序执行。

  4. <init>()方法每次调用构造方法都会执行。

案例

类加载与实例加载顺序

public class Father {
    private int i = test();
    private static int j = method();

    static {
        System.out.print(1);
    }

    public Father() {
        System.out.print(2);
    }

    {
        System.out.print(3);
    }

    public int test() {
        System.out.print(4);
        return 1;
    }

    public static int method(){
        System.out.print(5);
        return 1;
    }
}

public class Son extends Father {
    private int i = test();
    private static int j = method();

    static {
        System.out.print(6);
    }

    public Son() {
        System.out.print(7);
    }

    {
        System.out.print(8);
    }

    public int test() {
        System.out.print(9);
        return 1;
    }

    public static int method(){
        System.out.print(10);
        return 1;
    }

    public static void main(String[] args) {
        Son s1=new Son();
        System.out.println();
        Son s2 = new Son();
    }
}

结果:

51106932987
932987

若main函数改为空函数,则结果为:

51106

常量引用

public class ConstantReference {
    public static void main(String[] args) {
        System.out.println(ConstClass.HELLO);
    }

    private static class ConstClass{
        private static final String HELLO = "hello";

        static {
            System.out.println("ConstClass init.");
        }
    }
}

上面代码只会输出 hello,因为在编译阶段 ”hello“ 会存储在 ConstantReference 类的常量池中。

若把 HELLO 的 final 修饰符去掉,则会先打印 ”ConstClass init.“

父类静态变量引用

public class SuperStaticReference {

    public static void main(String[] args) {
        System.out.println(SubClass.value);
    }

    private static class SuperClass {
        static {
            System.out.println("SuperClass init!");
        }

        static int value = 123;
    }

    private static class SubClass extends SuperClass {
        static {
            System.out.println("SubClass init!");
        }
    }
}

// output
SuperClass init!
123

上面代码没有输出 ”SubClass init!“,对于静态字段,只有直接定义这个字段的类才会被初始化。

数组引用

public class ArrayReference {
    public static void main(String[] args) {
        SuperClass[] a = new SuperClass[10];
    }

    private static class SuperClass {
        static {
            System.out.println("SuperClass init!");
        }
    }
}

上面代码不会输出 ”SuperClass init!“。

初始值是,而不是代码中定义的值。

数据类型的 0 值