`
seaizon
  • 浏览: 145128 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

JVM原理学习—— 类的初始化(转)

    博客分类:
  • java
阅读更多
  类的初始化工作,主要是将静态变量、常量初始化为“正确”的值(也就是程序员希望设定的特定值而非其类型的默认值),以及其它一些需要在初始化类的时候需要做的工作(如读取配置文件等)。通常我们可以这样做:
Java代码

class A extends B {
    public static int intVal = 30;
    public static String strVal;
    
    static {
        strVal = readConfig("ItemA");
    }

    private static String readConfig(String key) {
        ....
    }
}



    当一个类被加载,它将顺序经历四个过程:验证、准备、解析、初始化(一个类被加载以前,如果其父类尚未初始化,那么JVM会先去用以上四个过程对这个父类进行初始化)。验证只是检查class文件是否符合java语义并且不会损害JVM的完整性,这里不多赘述。准备阶段是为类成员分配内存,同时根据该成员的类型赋给它相应的默认值,对于上面的示例类A,经过准备阶段后状态是这样的:
intVal = 0;
strVal = null;
    解析是把符号引用转为直接引用的过程,比如,原来JVM只知道类A有一个成员叫"intVal",通过解析则知道了该成员的地址是0xBBEDF,以后再使用这个成员的时候,就直接去这个内存地址去找了。同时在这个阶段,类的方法比如上面的readConfig()也会被映射到某个内存地址以待调用。
    初始化则是利用类定义的JAVA代码确定成员变量的初值(如果对某个成员没有相应的java代码对其进行初始赋值操作,那么它就沿用在准备阶段获得的该类型默认值)。在这个阶段,所有的静态代码都会被执行,事实上,类在编译时编译器是会把这些静态代码封装到一个<clinit>方法中去的,在使用这个类的时候,初始化过程就会调用这个<clinit>方法。这个方法程序员是不能调用的,它只能被JVM调用。

    以上对JVM初始化一个类的过程做了一些讲解,但是JVM究竟什么时候才会初始化一个类呢?总的来说,JVM会在“主动”使用一个类的时候将该类初始化。所谓“主动”,大致有6种已知的行为,对我们比较常见的是:1)试图创建该类的一个新实例;2)调用该类声明的一个静态方法;3)使用类中声明的非常量静态字段。考虑下面的例子:
Java代码

public interface Angry {
    String greeting = "Grrrr!";
    int angerLevel = Dog.getAngerLevel();
}

public class Dog implements Angry {
    public static final String greeting = "Wong, Wong, Wong!";
    
    static {
        System.out.println("Dog was initialized.");
    }

    public static int getAngerLevel() {
        System.out.println("Angry was initialized.");
        return 1;
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        testClassInit();
    }

    public static void testClassInit() throws Exception {

        //passive use of Angry
        System.out.println(Angry.greeting);

        //passive use of Dog
        System.out.println(Dog.greeting);
    }
}



    如果可以的话,看官可以先猜一猜输出的结果是什么。
    其实注释里已经提示得很清楚了,两个输出语句都是用被动方式调用的Angry和Dog的成员,因此无论是"Dog was initialized."还是"Angry was initialized."都不会被打印。换句话说,Angry和Dog都没有被初始化。
    为什么类没有被初始化但它的静态final成员还是可以正确打印呢?实际上,像声明为“public static final String”的静态常量(注意,在接口里声明String效果是一样的,它实际上也是个final常量),它在编译的时候已经在使用它的所有地方用这个常量值直接替换了,也就是说,经过编译,实际上主运行类变成了这样:
Java代码


public class Main {
    public static void main(String[] args) throws Exception {
        testClassInit();
    }

    public static void testClassInit() throws Exception {

        //passive use of Angry
        System.out.println("Grrrr!");

        //passive use of Dog
        System.out.println("Wong, Wong, Wong!");
    }
}



自然地,它打印结果的时候就无需初始化甚至无需加载相关的类了。

    实际中我的项目也有很多活生生的例子。比如,很多时候我们想要用一个类来管理项目中通用的常量,避免“魔数”的代码臭味,比如:
Java代码


class ConstManager {
    public static final String SIGN_DASH = "-";
    public static final String SIGN_SLASH = "/";
    public static final String SIGN_COMMA = ",";
    ......
}



然后我们会在项目的某处会以ConstManager.SIGN_COMMA 来代替逗号。这对我们管理项目是有益的,当需要修改一个符号的时候,只需要在一处修改再编译就行了。但实际上,编译后的class文件,在用到这些常量的代码块的位置,这些符号早就被替换成真实的","之类的值了。在项目运行的过程中,ConstManager甚至从来都没有机会被应用服务器加载。

原文:http://www.iteye.com/topic/512550
分享到:
评论

相关推荐

    Java起航 ---- 类的初始化历程

    本篇文章将深入探讨“Java起航——类的初始化历程”,并结合JVM(Java虚拟机)的工作原理,帮助你更好地理解这个过程。 首先,我们需要了解Java类的生命周期,它包括加载、验证、准备、解析和初始化五个阶段。当一...

    JVM底层原理课件PPT

    ### JVM底层原理——类加载子系统详解 #### 一、引言 Java虚拟机(JVM)作为Java程序运行的基础环境,其内部结构复杂且功能强大。本文将基于“JVM底层原理课件PPT”中关于类加载子系统的介绍进行深入解析。类加载子...

    深入JVM内核—原理、诊断与优化视频教程-3.常用JVM配置参数

    其中,类加载子系统负责加载、验证、准备和初始化类文件;运行时数据区包括堆、栈、方法区、程序计数器和本地方法栈,它们各自承担着不同的职责,如存储对象实例、管理方法执行上下文等;执行引擎是JVM的心脏,它...

    深入java虚拟机(二)——类的生命周期(上)类的加载和连接1

    本文将重点探讨类加载器的角色,以及类的加载、连接和初始化这三个阶段。 1. **类加载**: 类加载是JVM获取Java类字节码文件并将其转换为内存中`java.lang.Class`对象的过程。这个过程通常由类加载器完成。Java源...

    JVM学习笔记(一)——类的加载机制

    总结来说,类的加载机制是JVM中至关重要的部分,它确保了类的正确加载、验证和初始化,使得程序能够正常运行。理解类加载机制有助于优化程序性能,解决类加载相关的错误,并实现更灵活的代码管理。

    2021Java字节跳动面试题——面向字节_JVM(下).pdf

    5. **初始化**:这是类加载的最后一步,在之前的类加载过程中,除了在加载阶段用户应用程序可以通过自定义类加载器参与外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的Java程序代码...

    学习笔记——资料

    - **数组**:学习如何声明、初始化和操作一维或多维数组。 - **集合框架**:ArrayList、LinkedList、HashSet、HashMap等容器的理解和使用,以及它们之间的区别和应用场景。 4. **异常处理** - **异常分类**:...

    java基础之JVM

    5. **初始化**:为类的静态变量赋初始值。 **2.2 加载.class文件的方式** 加载`.class`文件的方式多样,常见的有: 1. **从本地系统直接加载**:最常见的加载方式,从本地文件系统加载。 2. **通过网络下载**:从...

    JVM笔记(阳哥).zip

    JVM的类加载机制包括加载、验证、准备、解析和初始化五个阶段。其中,加载是找到类的.class文件并读入内存;验证确保字节码的正确性;准备为类的静态变量分配内存并初始化为默认值;解析将符号引用转换为直接引用;...

    30+个视频+深入理解Java虚拟机(jvm优化+内存模型+虚拟机原理)

    其中,类的初始化阶段是执行类构造器`()`的地方,负责对类变量进行初始值设置。 #### 字节码解释与JIT编译 Java程序最初以字节码形式运行,由解释器解释执行。为了提高性能,JIT(Just-In-Time)编译器会在运行时将...

    Java JVM Instruction Set

    `main()`函数通常包含初始化参数`String[] args`,这部分的局部变量会在栈帧中分配空间。 ##### Min()函数的调用 当从`main()`函数中调用`Min()`函数时,JVM会创建一个新的栈帧来保存局部变量和参数,并跳转到相应...

    面试必问之jvm与性能优化.pdf

    - **初始化(Initialization)**:执行类构造器`()`方法,对类变量进行初始化。 #### 二、类加载器概述 **1. 定义** 类加载器是Java中用于加载类文件的组件。当Java程序运行时,类加载器负责从文件系统、网络等来源...

    mini-jvm使用 Java 8 实现 jvm

    在这个过程中,mini-jvm需要处理类的依赖关系,确保正确地初始化和加载类。 七、异常处理与垃圾回收 尽管mini-jvm简化了许多JVM的功能,但依然需要实现基本的异常处理框架。同时,虽然可能没有完全实现垃圾回收,...

    Java虚拟机类装载的原理及实现

    - **初始化**:执行类初始化代码,即执行类的静态初始化器和静态初始化块。 每个步骤都有其特定的作用,保证了类能够被正确且安全地加载和使用。 ##### 装载的实现 在JVM中,类的装载是由`ClassLoader`及其子类...

    library-template-jvm,一个kotlin/jvm库模板(带有一个示例项目)。.zip

    这样,开发者可以直接利用这个模板进行新库的初始化,无需从零开始设置各种环境,极大地提高了开发效率。 在深入探讨这个模板之前,我们先了解一下Gradle,它是项目构建的首选工具,尤其是在Java和Kotlin生态系统中...

    ImagesForJVM-JVM笔记图片

    【描述】"ImagesForJVM——JVM笔记图片" 暗示这些图片可能是教学或学习笔记的一部分,旨在通过视觉化的方式解释JVM的关键概念,如内存模型、类加载机制、垃圾收集以及性能优化等方面。 【标签】"java" 明确了这些...

    jvm-demo.zip

    JVM的类加载机制包括加载、验证、准备、解析和初始化五个阶段。"jvm-demo"可能包含相关的类加载示例,帮助我们理解类如何被动态地加载到内存中,并进行初始化。 3. **运行时数据区** JVM内部划分了不同的区域来...

    Java JDK 6学习笔记——ppt简体版

    了解构造函数的作用,它是初始化新创建的对象时调用的方法。 6. **包与访问修饰符**:Java使用包来组织类,提供命名空间和访问控制。访问修饰符有public、private、protected和默认(包级私有),它们决定了类、...

    JVM脑图.zip

    其中,类加载子系统负责加载、验证、准备和初始化类;运行时数据区包括堆、栈、方法区、程序计数器和本地方法栈,用于存储程序运行时的数据。 2. **类加载机制** 类加载分为加载、验证、准备、解析和初始化五个...

    jvm参数调优-jvmSample.zip

    《JVM参数调优——深度解析与实践指南》 在Java开发中,JVM(Java Virtual Machine)扮演着至关重要的...通过对"jvmSample-master"这样的实战案例学习,我们可以更好地理解JVM的工作原理,提高我们的Java应用性能。

Global site tag (gtag.js) - Google Analytics