`
dengminhui
  • 浏览: 167917 次
  • 来自: ...
社区版块
存档分类
最新评论

JVM原理学习笔记(三) —— 类的初始化

阅读更多

最近在阅读 《Inside the JVM》 这本书,结合一些日常工作学习中的感想,随便写一些东西,蜻蜓点水,不必有章法。

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

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)使用类中声明的非常量静 态字段。考虑下面的例子:

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常量),它在编译的时候已经在使用它的所有地方用这个 常量值直接替换了,也就是说,经过编译,实际上主运行类变成了这样:

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


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

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

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作为一种广泛应用的高级编程语言,是软件开发领域的核心力量。这份"学习笔记——资料"涵盖了Java学习的各个方面,旨在帮助初学者和有经验的开发者巩固基础,提升技能。以下是对这...

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

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

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

    Java JDK 6学习笔记——PPT简体版是针对初学者和有经验的开发者们的一份宝贵资源,它深入浅出地介绍了Java编程语言的核心概念和技术。这份笔记以PPT的形式呈现,使得学习过程更加直观易懂,适合课堂教学或自我学习。...

    JVM笔记(阳哥).zip

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

    JVM学习笔记核心知识点整理

    ### JVM学习笔记核心知识点整理 #### 一、引言与背景 随着软件开发技术的不断发展,Java作为一种广泛应用的编程语言,其背后的核心技术——Java虚拟机(JVM)的重要性日益凸显。掌握JVM不仅可以帮助开发者更好地理解...

    ImagesForJVM-JVM笔记图片

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

    Java,JVM相关笔记的代码知识

    类加载分为加载、验证、准备、解析和初始化五个阶段,每个阶段都有其特定的任务和目的,如确保类的正确性和内存分配。 2. **运行时数据区**:JVM在运行时会创建几个不同的数据区域,包括程序计数器、虚拟机栈、本地...

    Java JDK 7学习笔记(国内第一本Java 7,前期版本累计销量5万册)

     《Java JDK 7学习笔记》详细介绍了JVM、JRE、Java SE API、JDK与IDE之间的对应关系。必须要时从Java SE API的源代码分析,了解各种语法在Java SE API中如何应用。  《Java JDK 7学习笔记》将IDE操作纳为教学内容...

    (完整版)Java笔记总结.pdf

    数组的定义方式有三种:动态初始化、静态初始化和结合初始化。冒泡排序是常见的排序算法,对于 n 个元素,进行 n-1 轮排序,每轮排序进行 n-1 次比较。 二维数组可以理解为数组的数组,定义方式有三种:完全指定...

    CoreJava学习笔记

    ### CoreJava学习笔记 #### 一、JAVA特点与运行原理 **JAVA特点:** 1. **简单性**:Java的设计者们将C++语言中许多不易理解和容易混淆的部分去除,使得Java更容易理解与掌握。 2. **面向对象**:Java几乎一切都...

    java学习笔记-基础

    ### Java学习笔记——基础知识详解 #### 一、Java开发环境(JDK)与运行环境(JRE) Java技术的核心在于其强大的跨平台能力,这主要得益于Java的两大环境:JDK(Java Development Kit)和JRE(Java Runtime ...

    [Java学习笔记doc]-javase基本知识

    **Java学习笔记——Java SE基本知识** Java是一种广泛使用的面向对象的编程语言,以其跨平台、安全性高和可移植性而闻名。Java Standard Edition(Java SE)是Java平台的基础,它提供了开发和运行桌面应用程序、...

    良葛格Java JDK 5.0学习笔记

    匿名内部类可以简化单个接口实现的情况,而var关键字(在Java 10才正式引入,但这里提到可能是早期的概念讨论)则允许编译器根据初始化表达式推断变量的类型,使得代码更加简洁。 此外,Java 5还引入了注解...

    java学习笔记

    ### Java学习笔记——设计模式与基础概念解析 #### 一、设计模式概述 设计模式是在软件开发过程中,针对常见的问题提出的经过验证的解决方案。这些模式是开发者们在长期实践中不断提炼和完善的结果,能够帮助...

    java学习笔记,java基础知识整理

    ### Java学习笔记——Java基础知识整理 #### 一、Java技术入门 Java是一种广泛使用的编程语言,因其跨平台性、安全性和高效性而受到青睐。Java最初由Sun Microsystems开发,并于1995年首次发布。 ##### 1. Sun ...

    JAVA面向对象编程(孙卫琴)学习笔记

    变量是存储数据的容器,理解它们的声明、初始化和使用是编写任何Java程序的基础。 "JAVA面向对象编程(孙卫琴)_3java操作符1.doc"和"JAVA面向对象编程(孙卫琴)_3java操作符.doc"讲解了Java中的运算符,包括算术...

    java复习笔记

    构造器是用于初始化新创建对象的特殊方法,Java中的构造器名与类名相同。 四、异常处理 Java的异常处理机制使得程序能够优雅地处理错误,通过try-catch-finally语句块捕获并处理异常。异常类继承自java.lang....

    深入java虚拟机读后笔记

    3. **初始化阶段**:在类加载完成后,JVM会根据初始化指令为类的静态变量赋予初始值,并执行静态块中的代码。 #### 三、类加载机制 类加载过程是Java程序动态性的重要体现,它包括以下几个步骤: 1. **加载**:...

    韩顺平 Java从入门到精通视频教程(全94讲)学习笔记整理(完整清晰版)

    - **变量与常量**:讲解变量的定义、初始化及作用域,以及常量的特点与使用。 - **运算符与表达式**:覆盖各种运算符(算术运算符、比较运算符等)及其使用方法。 - **流程控制语句**:包括条件判断语句(if-else、...

Global site tag (gtag.js) - Google Analytics