- 浏览: 30739 次
- 性别:
- 来自: 广州
最近访客 更多访客>>
最新评论
-
DragCheng:
这标题亮了
深入研究java.long.Class类(转) -
油炸大龙虾:
这个标题害人啊,哎……
深入研究java.long.Class类(转)
类的初始化工作,主要是将静态变量、常量初始化为“正确”的值(也就是程序员希望设定的特定值而非其类型的默认值),以及其它一些需要在初始化类的时候需要做的工作(如读取配置文件等)。通常我们可以这样做:
Java代码
当一个类被加载,它将顺序经历四个过程:验证、准备、解析、初始化(一个类被加载以前,如果其父类尚未初始化,那么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代码
如果可以的话,看官可以先猜一猜输出的结果是什么。
其实注释里已经提示得很清楚了,两个输出语句都是用被动方式调用的Angry和Dog的成员,因此无论是"Dog was initialized."还是"Angry was initialized."都不会被打印。换句话说,Angry和Dog都没有被初始化。
为什么类没有被初始化但它的静态final成员还是可以正确打印呢?实际上,像声明为“public static final String”的静态常量(注意,在接口里声明String效果是一样的,它实际上也是个final常量),它在编译的时候已经在使用它的所有地方用这个常量值直接替换了,也就是说,经过编译,实际上主运行类变成了这样:
Java代码
自然地,它打印结果的时候就无需初始化甚至无需加载相关的类了。
实际中我的项目也有很多活生生的例子。比如,很多时候我们想要用一个类来管理项目中通用的常量,避免“魔数”的代码臭味,比如:
Java代码
然后我们会在项目的某处会以ConstManager.SIGN_COMMA 来代替逗号。这对我们管理项目是有益的,当需要修改一个符号的时候,只需要在一处修改再编译就行了。但实际上,编译后的class文件,在用到这些常量的代码块的位置,这些符号早就被替换成真实的","之类的值了。在项目运行的过程中,ConstManager甚至从来都没有机会被应用服务器加载。
原文:http://www.iteye.com/topic/512550
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内存溢出解析(转)
2010-01-13 15:16 758JAVA内存溢出解析 核心 ... -
Java的内存泄漏(转)
2010-01-13 14:36 416问题的提出 Java 的一个重要优点就是通过垃圾收集器(Ga ... -
Java方法继承、方法重载、方法覆盖小总结(转)
2010-01-06 17:21 993Java方法继承、方法重载 ... -
JVM原理学习 —— 虚拟机规范(转)
2010-01-05 16:51 970《Inside the JVM》一开始就指出,所谓“虚拟机”实 ... -
深入探索Java工作原理:JVM,内存回收及其他
2010-01-05 16:43 937深入探索Java工作原理: ... -
java里类的继承机制-成员变量(转)
2009-12-31 14:03 2175在网上看见一个关于java ... -
java里类的继承机制-构造方法(转)
2009-12-31 14:00 934这次我想深入探究以下java里类的继承机制。 我们知道,继承是 ... -
java 继承类 变量、静态变量、构造函数执行顺序(转)
2009-12-31 13:35 1997java 继承类 变量、静态变量、构造函数执行顺序 class ... -
map,set,list,等JAVA中集合解析
2009-12-30 15:51 1337map,set,list,等JAVA中集合 ... -
Class.getResourceAsStream 和 ClassLoader.getResourceAsStream
2009-12-29 11:21 653两个都可以用于从 classpath 里面进行资源读取, c ... -
JTA和JDBC事务
2009-12-28 15:44 888JTA和JDBC事务(转) 一般情况下,J2EE应用服务器 ... -
深入研究java.long.Class类(转)
2009-12-27 23:13 981前言:Java的类库日益庞大,所包含的类和接口也不计其数。但其 ... -
Java关键字之native,strictfp,transient,volatile
2009-12-21 14:04 587Java关键字(keywords) abstrac ... -
javap的使用
2009-12-16 22:38 710javap简介 原文网址 http://www.javare ... -
JAVA 基本数据类型取值范围
2009-12-16 15:55 1230先看一段代码 public class ... -
Tomcat启动分析
2009-12-14 17:23 1440Tomcat启动分析 核心提示:用 文本编辑工具打开用于启动T ... -
servlet的介绍
2009-12-14 17:14 523servlet的介绍 关键字: servlet的介绍 在 e ...
相关推荐
本篇文章将深入探讨“Java起航——类的初始化历程”,并结合JVM(Java虚拟机)的工作原理,帮助你更好地理解这个过程。 首先,我们需要了解Java类的生命周期,它包括加载、验证、准备、解析和初始化五个阶段。当一...
### JVM底层原理——类加载子系统详解 #### 一、引言 Java虚拟机(JVM)作为Java程序运行的基础环境,其内部结构复杂且功能强大。本文将基于“JVM底层原理课件PPT”中关于类加载子系统的介绍进行深入解析。类加载子...
其中,类加载子系统负责加载、验证、准备和初始化类文件;运行时数据区包括堆、栈、方法区、程序计数器和本地方法栈,它们各自承担着不同的职责,如存储对象实例、管理方法执行上下文等;执行引擎是JVM的心脏,它...
本文将重点探讨类加载器的角色,以及类的加载、连接和初始化这三个阶段。 1. **类加载**: 类加载是JVM获取Java类字节码文件并将其转换为内存中`java.lang.Class`对象的过程。这个过程通常由类加载器完成。Java源...
总结来说,类的加载机制是JVM中至关重要的部分,它确保了类的正确加载、验证和初始化,使得程序能够正常运行。理解类加载机制有助于优化程序性能,解决类加载相关的错误,并实现更灵活的代码管理。
5. **初始化**:这是类加载的最后一步,在之前的类加载过程中,除了在加载阶段用户应用程序可以通过自定义类加载器参与外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的Java程序代码...
- **数组**:学习如何声明、初始化和操作一维或多维数组。 - **集合框架**:ArrayList、LinkedList、HashSet、HashMap等容器的理解和使用,以及它们之间的区别和应用场景。 4. **异常处理** - **异常分类**:...
5. **初始化**:为类的静态变量赋初始值。 **2.2 加载.class文件的方式** 加载`.class`文件的方式多样,常见的有: 1. **从本地系统直接加载**:最常见的加载方式,从本地文件系统加载。 2. **通过网络下载**:从...
JVM的类加载机制包括加载、验证、准备、解析和初始化五个阶段。其中,加载是找到类的.class文件并读入内存;验证确保字节码的正确性;准备为类的静态变量分配内存并初始化为默认值;解析将符号引用转换为直接引用;...
其中,类的初始化阶段是执行类构造器`()`的地方,负责对类变量进行初始值设置。 #### 字节码解释与JIT编译 Java程序最初以字节码形式运行,由解释器解释执行。为了提高性能,JIT(Just-In-Time)编译器会在运行时将...
`main()`函数通常包含初始化参数`String[] args`,这部分的局部变量会在栈帧中分配空间。 ##### Min()函数的调用 当从`main()`函数中调用`Min()`函数时,JVM会创建一个新的栈帧来保存局部变量和参数,并跳转到相应...
- **初始化(Initialization)**:执行类构造器`()`方法,对类变量进行初始化。 #### 二、类加载器概述 **1. 定义** 类加载器是Java中用于加载类文件的组件。当Java程序运行时,类加载器负责从文件系统、网络等来源...
在这个过程中,mini-jvm需要处理类的依赖关系,确保正确地初始化和加载类。 七、异常处理与垃圾回收 尽管mini-jvm简化了许多JVM的功能,但依然需要实现基本的异常处理框架。同时,虽然可能没有完全实现垃圾回收,...
- **初始化**:执行类初始化代码,即执行类的静态初始化器和静态初始化块。 每个步骤都有其特定的作用,保证了类能够被正确且安全地加载和使用。 ##### 装载的实现 在JVM中,类的装载是由`ClassLoader`及其子类...
这样,开发者可以直接利用这个模板进行新库的初始化,无需从零开始设置各种环境,极大地提高了开发效率。 在深入探讨这个模板之前,我们先了解一下Gradle,它是项目构建的首选工具,尤其是在Java和Kotlin生态系统中...
【描述】"ImagesForJVM——JVM笔记图片" 暗示这些图片可能是教学或学习笔记的一部分,旨在通过视觉化的方式解释JVM的关键概念,如内存模型、类加载机制、垃圾收集以及性能优化等方面。 【标签】"java" 明确了这些...
JVM的类加载机制包括加载、验证、准备、解析和初始化五个阶段。"jvm-demo"可能包含相关的类加载示例,帮助我们理解类如何被动态地加载到内存中,并进行初始化。 3. **运行时数据区** JVM内部划分了不同的区域来...
了解构造函数的作用,它是初始化新创建的对象时调用的方法。 6. **包与访问修饰符**:Java使用包来组织类,提供命名空间和访问控制。访问修饰符有public、private、protected和默认(包级私有),它们决定了类、...
其中,类加载子系统负责加载、验证、准备和初始化类;运行时数据区包括堆、栈、方法区、程序计数器和本地方法栈,用于存储程序运行时的数据。 2. **类加载机制** 类加载分为加载、验证、准备、解析和初始化五个...
《JVM参数调优——深度解析与实践指南》 在Java开发中,JVM(Java Virtual Machine)扮演着至关重要的...通过对"jvmSample-master"这样的实战案例学习,我们可以更好地理解JVM的工作原理,提高我们的Java应用性能。