- 浏览: 202098 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
fireway200:
good job good job
深入理解JVM--JVM垃圾回收机制 -
sinat_19635357:
good job
深入理解JVM--JVM垃圾回收机制 -
jayung:
不错,非常感谢
Eclipse正则表达式 替换查找 /* */ 注释 -
yuanwofei:
[c[color=darkblue][color=cyan][ ...
深入理解JVM—JVM内存模型 -
w10001:
非常感谢,花费2个小时,按照楼主的方法终于成功了
ext4.1 spket 1.6.23 Myeclipse10.5 开发环境 extjs代码提示
类的初始化
静态变量的生民语句以及静态代码块都被看作类的初始化语句,Java虚拟机会按照初始化语句在类文件中的先后顺序来依次夹在他们。
1、 a被初始化为默认值0
2、 a被赋予正确的初始值1
3、 执行静态代码块,将a的值赋为2
4、 执行静态代码块,将a的值赋为4
因此最终的执行结果是4
一个类只能被一个ClassLoader加载一次,只有没有被加载过的类或者已经被卸载的类才可能 被再次加载。类的初始化步骤如下:
1、 假如这个类还没有被加载和连接,那就先进行加载和连接
2、 加入存在直接的父类,并且这个父类还没有被初始化则先初始化直接的父类
3、 假如类中存在初始化语句,那就依次执行初始化语句。
注意:Java虚拟机在初始化一个类的时候要求它的父类已经被初始化,但是这条规则并不适应于接口!在初始化一个类的时候并不会初始化他所实现的接口!在初始化一个接口的时候也不会去初始化他的父接口!因此一个父接口并不会因为他的实现类或者子接口的初始化而初始化,只有当程序使用该接口特定的静态变量的时候才会去初始化这个接口!
我们上面的例子印证了第三点,对于前两点我们知道我们构造一个类的时候假设它有父类,就会默认调用父类的无参构造方法,然后就初始化了父类,而初始化之前必须进行加载和连接!
我们来看一个具体的程序来验证上面的结论!
package com.yhj.jvm.classloader.finalTest;
/**
* @Description:父类
* @Author YHJ create at 2011-6-26 下午03:36:50
* @FileName com.yhj.jvm.classloader.finalTest.$Parent.java
*/
class Parent{
static int a=1;
static{
System.out.println("Parent's static block");
}
}
/**
* @Description:子类
* @Author YHJ create at 2011-6-26 下午03:37:04
* @FileName com.yhj.jvm.classloader.finalTest.$Child.java
*/
class Child extends Parent{
static int b=2;
static{
System.out.println("Parent's static block");
}
}
/**
* @Description:初始化测试用例
* @Author YHJ create at 2011-6-26 下午03:28:35
* @FileName com.yhj.jvm.classloader.finalTest.InitTestCase.java
*/
public class InitTestCase {
static{
System.out.println("InitTestCase's static block");
}
public static void main(String[] args) {
System.out.println(Child.b);
}
}
这个程序很简单,我们一猜就能知道结果,因为是InitTestCase启动类,因此优先初始化!然后嗲用子类Child的b静态变量,Child继承自Parent,因此先初始化父类Parent,所以运行结果是:
package com.yhj.jvm.classloader.finalTest;
/**
* @Description:父类
* @Author YHJ create at 2011-6-26 下午03:36:50
* @FileName com.yhj.jvm.classloader.finalTest.$Parent.java
*/
class Parent{
static int a=1;
static{
System.out.println("Parent's static block");
}
}
/**
* @Description:子类
* @Author YHJ create at 2011-6-26 下午03:37:04
* @FileName com.yhj.jvm.classloader.finalTest.$Child.java
*/
class Child extends Parent{
static int b=2;
static{
System.out.println("Parent's static block");
}
}
/**
* @Description:初始化测试用例
* @Author YHJ create at 2011-6-26 下午03:28:35
* @FileName com.yhj.jvm.classloader.finalTest.InitTestCase.java
*/
public class InitTestCase {
static{
System.out.println("InitTestCase's static block");
}
public static void main(String[] args) {
Parent parent;
System.out.println("===== split line =====");
parent=new Child();
System.out.println(Parent.a);
System.out.println(Child.b);
}
}
为了能够看清楚parent具体的初始化状态,我们加入split line来隔开程序段,这样又会返回怎样的结果呢?
刚开始的Parent是否会初始化?
我们之前已经说的很清楚了,只有主动使用的6种情况会导致类的初始化,因此刚开始parent不会初始化,因为InitTestCase是启动类,所以最先初始化,然后是分隔符,然后初始化子类Child,初始化Child的时候发现继承了Parent,所以先初始化Parent,然后初始化Child,然后再次调用parent的静态变量,因为Parent已经初始化了,一个类只能被一个ClassLoader初始化一次,所以不会初始化Parent,直接输出Parent.a的数据,Child同理,因此最终执行结果是:
1、 创建类的实例
2、 访问某个类或接口的静态变量,或者对该静态变量赋值
3、 调用类的静态方法
4、 反射(如Class.forName(“com.yhj.jvm.classloader.finalTest.TestCase”))
5、 初始化一个类的子类
6、 Java虚拟机启动时被标明为启动类的类(Java Test)
除了以上6种情况都属于被动使用,不会导致类的初始化。
我们来看这样一个程序
/**
* @Description:静态成员测试
* @Author YHJ create at 2011-6-26 下午02:54:23
* @FileName com.yhj.jvm.classloader.finalTest.$StaticClassTest.java
*/
class StaticClassTest{
public static int staticValue = 2 / 1;
static{
System.out.println("StaticClassTest's static block!");
}
}
/**
* @Description: 测试用例:用于测试
* @Author YHJ create at 2011-6-26 下午02:52:58
* @FileName com.yhj.jvm.classloader.finalTest.TestCase.java
*/
public class TestCase {
public static void main(String[] args) {
System.out.println(StaticClassTest.staticValue);
}
}
很显然属于调用类的静态成员变量,类会被初始化,初始化就会执行执行静态初始化语句块,就会执行System.out.println("StaticClassTest's static block!");语句,因此运行结果如下
如下代码
package com.yhj.jvm.classloader.finalTest;
import java.util.Random;
/**
* @Description:静态成员测试
* @Author YHJ create at 2011-6-26 下午02:54:23
* @FileName com.yhj.jvm.classloader.finalTest.$StaticClassTest.java
*/
class StaticClassTest{
public static int staticValue = 2 / 1;
static{
System.out.println("StaticClassTest's static block!");
}
}
//===================================================================
/**
* @Description:Final成员测试1
* @Author YHJ create at 2011-6-26 下午02:56:36
* @FileName com.yhj.jvm.classloader.finalTest.$StaticFinalTest1.java
*/
class StaticFinalTest1{
public final static int staticValue = 2 / 1;
static{
System.out.println("StaticFinalTest1's static block!");
}
}
//===================================================================
/**
* @Description:Final成员测试2
* @Author YHJ create at 2011-6-26 下午02:56:46
* @FileName com.yhj.jvm.classloader.finalTest.TestCase.$StaticFinalTest2.java
*/
class StaticFinalTest2{
public final static int staticValue = new Random().nextInt(10);
static{
System.out.println("StaticFinalTest2's static block!");
}
}
//===================================================================
/**
* @Description: 测试用例:用于测试
* @Author YHJ create at 2011-6-26 下午02:52:58
* @FileName com.yhj.jvm.classloader.finalTest.TestCase.java
*/
public class TestCase {
public static void main(String[] args) {
System.out.println(StaticClassTest.staticValue);
System.out.println(StaticFinalTest1.staticValue);
System.out.println(StaticFinalTest2.staticValue);
}
}
第一个我们已经知道了,会执行静态代码块,那第二个和第三个呢?他们的区别是第二个是在第一个的基础之上将staticValue变为了final,第三个对于第二个的区别是第三个static不是一个计算的具体值,而是0-10之间的一个随机数!又有什么样的区别呢?我们先来看一下运行结果!
这是为什么呢?我们再来看一下他们的区别:StaticFinalTest1的静态常量值是2/1=2,对于这种值在编译的时候JVM就会把结果计算出来放进class文件中,相当于StaticFinalTest1=2,而StaticFinalTest2在编译的时候并不知道具体的数值是多少,需要运行的时候才会被赋值,所以我们可以看出,调用编译时的静态常量并不会初始化这个类(即不属于主动使用),而调用运行时的静态常量是会初始化该类的!
我们再来改动一下上面父子类的程序
package com.yhj.jvm.classloader.finalTest;
/**
* @Description:父类
*/
class Parent{
static int a=1;
static{
System.out.println("Parent's static block");
}
}
/**
* @Description:子类
*/
class Child extends Parent{
static int b=2;
static{
System.out.println("Parent's static block");
}
}
/**
* @Description:初始化测试用例
*/
public class InitTestCase {
public static void main(String[] args) {
System.out.println(Child.a);
}
}
这样执行结果有什么呢?我们直接调用子类中父类定义的a会怎样呢?
按照我们之前的理论,执行结果应该是调用子类,先初始化父类,我们看下执行结果
注意:JVM规范规定只有当程序访问的静态变量或静态方法确实在当前类或当前接口中定义时,才可以认为是对类或接口的主动使用,所以我们直接调用Child中没有定义的a不属于对Child的主动使用,因此没有初始化Child!
注意:调用ClassLoader类的loadClass方法加载一个类,并不是对类的主动使用,不会导致类的初始化。
我们来看一下loadClass的API文档
二进制名称我们可以理解为类的全称,如上图中的类、内部类、匿名内部类等!
以前我们写的类都是通过启动类或者Web容器帮我们加载的,这里我们可以看到ClassLoader可以直接加载载这个类,但是我们看到这个类ClassLoader是抽象类
也就是说我们无法通过
我们知道如果这个类不能实例化,我们可以通过他的静态方法访问这个类,我们来看一下ClassLoader的一个静态方法getSysytemClassLoader()这个方法
我们看这段程序
package com.yhj.jvm.classloader.finalTest;
/**
* @Description;
*/
class Test{
static{
System.out.println("Test's static block");
}
}
/**
* @Description:ClassLoader测试用例
*/
public class ClassLoaderTestCase {
public static void main(String[] args) throws ClassNotFoundException {
ClassLoader classLoader=ClassLoader.getSystemClassLoader();
System.out.println("ClassLoader:"+classLoader);
Class<?>testClass=classLoader.loadClass("com.yhj.jvm.classloader.finalTest.Test");
System.out.println("using class.forName('com.yhj.jvm.classloader.finalTest.Test')");
testClass=Class.forName("com.yhj.jvm.classloader.finalTest.Test");
}
}
这段程序执行下来,我们来看下运行结果
很显然,这段程序当调用
从加载到连接到初始化,我们看到
发表评论
-
深入理解ClassLoader(五)—类的卸载
2012-06-28 10:37 1909我们知道,当一个类被加载、连接和初始化之后,他的生命周期 ... -
深入理解ClassLoader(四)—类的父委托加载机制
2012-06-28 10:35 2446上几次我们介绍到了JVM内部的几个类加载器,我们来重新画 ... -
深入剖析Classloader(二)--根类加载器,扩展类加载器与系统类加载器
2012-06-28 10:30 1382类的加载的最终产品是位于堆(heap)中的clas ... -
深入剖析Classloader(一)--类的主动使用与被动使用
2012-06-28 10:28 1302我们知道 java 运行的是这样的,首先 ... -
ext4.1 spket 1.6.23 Myeclipse10.5 开发环境 extjs代码提示
2012-06-27 10:26 5238用于在spket中进行提醒时的筛选。以下是具体的操作步骤 ... -
Eclipse HTMLEditor 下载安装
2012-06-26 17:13 1292需求:需要在eclipse里面编辑html和jsp,语法 ... -
MyEclipse 10.5 下载 破解
2012-06-26 08:22 249官方下载地址(Windows) ... -
MyEclipse 10.5 下载
2011-11-04 11:36 159Myeclipse 10.5(Windows) ... -
CAS sso单点登录 架设中问题及解决方案
2011-05-20 09:02 5790<转> 1.在CAS ... -
CAS 单点登录完整教程 【转】
2011-05-20 08:53 6702一、教程前言 教程 ... -
Myeclipse 9.0 10.0安装 SVN 插件
2011-03-28 16:21 5796方法一: 安装subclipse, SVN 插件 1、从官 ... -
MyEclipse 9.0 正式版 破解 注册机 新鲜出炉
2011-03-08 22:08 9935[原文] http://www.byshang.org/doc ... -
commons-beanutils 复制 bean 属性
2011-02-28 09:42 1598commons-beanutils是jakarta com ... -
MyEclipse 9.0 M2 官方下载地址
2011-02-10 11:43 6754注册机 现在已经出来了 大家赶紧下载去吧 下载地址:ht ... -
Eclipse正则表达式 替换查找 /* */ 注释
2010-12-13 15:53 8447最近几天用jd-gui反编译了一个springMVC的项 ... -
Myeclipse9.0安装VSS插件
2010-12-13 10:07 4006一、下载VSS插件 可以去官方网站下载,也可以在这里http: ...
相关推荐
ClassLoader类加载器讲解,理解JAVA类加载机制
【图解版】深入分析ClassLoader类加载工作机制,从原理到JVM的装载过程,详情分析了ClassLoader加载类以及自定义类加载器的过程,不可用于商业用途,如有版权问题,请联系删除!
ClassLoader的API使用和自定义
类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一。它使得 Java 类可以被动态加载到 Java 虚拟机中并执行。类加载器从 JDK 1.0 就出现了,最初是为了满足 Java Applet 的需要而开发出来的。Java ...
java应用程序类加载器(ClassLoader for java Application),类似exe4j, 方便启动java程序, 配置灵活,支持多平台选择性配置
ClassLoader类加载机制和原理详解
类加载器分为根加载器(bootstrap classloader)、扩展类加载器(ext classloader)、系统类加载器(system classloader)、自定义类加载器(通常继承java.net.URLClassLoader,重写findClass()),它们的关系通常...
下面小编就为大家带来一篇classloader类加载器_基于java类的加载方式详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一。它使得 Java 类可以被动态加载到 Java 虚拟机中并执行。类加载器从 JDK 1.0 就出现了,最初是为了满足 Java Applet 的需要而开发出来的。Java ...
如果户创建的JAR放在此录下,也会动由扩展类加载器加载.应程序类加载器(系统类加载器,Application ClassLoader)java语编写,由sun.
ClassLoader 三种类加载方式 Boostrap Extenxsion 以及Application ClassLoad分别适用的场景
jvm运行的过程中,需要载入类,而类的加载需要类加载器,本文章提供了java的类加载器的工作原理。可以使读者更加理解jvm的运行机制。
Java的类加载机制:加载,连接,初始化。JAVA类加载器: Bootstrap ClassLoader : 根类加载器, Extension ClassLoader: 扩展类加载器, System ClassLoader : 系统类加载器, Java反射
ClassLoader,,深入java加载器,,深入java加载器源代码
内嵌在JVM内核中的加载器,由C++语言编写(因此也不会继承ClassLoader),是类加载器层次中最顶层的加载器。用于加载java的核心类库,即加载jre/lib/rt.jar里所有的class。由于启动类加载器涉及到虚拟机本
类加载器是Java最强大的特征之一。但是开发者常常忘记类加载组件。类加载器是在运行时负责寻找和加载类文件的类。Java允许使用不同的类加载器,甚至自定义的类加载器。类加载器从源文件(通常是.class 或 .jar文件)...
关于类加载器的 上课ppt -java虚拟机自带的加载器 根类加载器(Bootstrap) c++写的看不到扩展类加载器(extension) 系统类加载器(System) AppClassLoad 用户自定义的类加载器 Java.lang.ClassLoader的子类
简单的自定义类加载器问候世界hello word,基于磁盘的ClassLoader
JDK(Java Development Kit) 是 Java 语言的软件开发工具包(SDK)。 SE(J2SE),standard edition,标准版,是我们通常用的一个版本,从JDK 5.0开始,改名为Java SE。
java ClassLoader的学习 java是一门解释执行的语言,由开发人员编写好的java源文件先编译成字节码文件.class... 一个类如果要被JVM所调度执行,必须先把这个类加载到JVM内存里,java.lang下有个很重要的类ClassL