`
longgangbai
  • 浏览: 7340073 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

类的初始化的时机的研究(实例学习讲解)

阅读更多
package com.easyway.commons.ispace.dev.lang.classloader;
/**
 * 关于类的初始化的时机的研究:
 * 
 * java虚拟机只有在程序首次主动使用一个类或者接口时,才会初始化。
 * 只有6种活动看作是程序对类或者接口的主动使用。
 * (1) 创建类的实例,创建实例类的途径包括:用new 语句创建实例或者通过反射,克隆以及序列化
 *   手段来创建实例。
 * (2) 调用类的静态方法
 * (3) 访问某一个类或者接口的常量或者对类的静态变量赋值。
 * (4) 调用java API 中某些反射方法。如:调用Class.forName()时,类没有被初始化,
 *    那么调用方法就会初始化这个类,然后返回类的实例。备注:forName()方法是java.lang.Class的静态方法。
 * (5) 初始化一个类的子类。例如对Sub的初始化,相等于对它父类Base类的主动使用,因此会先初始化Base类。
 * (6) java虚拟机启动时被标明为启动类的类。例如对于 java ClassCircleLine 命令,ClassCircleLine
 *    类就是启动类, java虚拟机会先初始化它。
 *    除了上述6中情况之外,其他使用java类的方式都被看作是被动使用。都不会导致类的初始化。
 * @author longgangbai
 * @date 2010-5-7
 * @version 1.0
 * @since JDK6.0
 */
class shape{
	static int a=1;
	static{
		System.out.println("init shape  static ");
	}
	/**
	 * (4)只有当程序访问的静态变量或者静态方法的确在当前类或者接口中定义是,才可看作是对类或者接口的主动调用。
	 * 例如Range.a 和Range.method(),由于静态变量a 和静态方法method()在shape父类中定义,
	 * 因此java虚拟机仅仅初始化父类shape,而没有初始化Range。
	 */
	static void method(){
		System.out.println("static void method");
	}
}
/**
 * (3) 当java 虚拟机初始化一个类时,要求他的所有父类都被初始化。但是这个规则并不适用接口
 * A. 在初始化一个类时,并不会先初始化它所实现的接口。
 * B. 在初始化一个接口时,并不会先初始化它的父类接口。
 * 因此一个父类接口并不会因为它的子即可或者实现类的初始化而初始化。
 * 只有当程序首次使用特定的静态变量时,才会导致该接口的初始化。
 */
class Range extends shape{
	static int b=1;
	
	static{
		System.out.println("init Range  static");
		System.out.println("now init Range");
		
	}
}
class ClassLoad{
	static{
		System.out.println("init ClassCircleLine");
	}
	/**
	 * 输入结果如下:
	 * init ClassLoad  首先启动连接ClassLoad 
	 *init shape  static   调用  Range.a 开始执行父类的初始化语句
     * a =1    //在初始化之后才执行代码 
	 * static void method
	 * 
	 * 
	 * @param args
	 * @throws ClassNotFoundException 
	 */
	public static void main(String[] args) {
		System.out.println(" a ="+Range.a);
		Range.method();
	}
}
public class ClassCircleLine {
	/**
	 *  (1)对于final 类型的静态变量,如果在编译时 不能计算出变量的值。那么这种变量使用看作是对类的主动调用,会导致初始化。
	 *  由于编译器不会计算变量m的值,因此变量m不是编译时常量。当被调用时,java虚拟机会初始化该类,是的变量a在方法区拥有特定的内存和初始值。
	 */
	private static final double m=Math.random()*5; //变量m不是编译时的常量
	/**
	 *  (2)当java虚拟机加载并连接类是,不会再方法区内为它的编译时常量分配内存。
	 * 对于final 类型的静态变量,如果在编译时就能计算出变量的取值。那么这种变量看作编译时的常量。
	 * java程序中队类中的编译时常量的使用,被看作是对类的被动使用,不会导致类的初始化。
	 */
	private static final int a=2*3;  //变量a是 编译时的常量
	
	static{
		System.out.println("init ClassCircleLine");
	}
	/**
	 * 输入结果如下:
	 * after loader ClassLoad 
     * before init ClassLoad 
     * init ClassCircleLine
     * (5) 调用ClassLoader类的loadClass()方法加载一个雷,并不是对类的主动使用,不会导致类的初始化,
	 * 在main方法中,系统类加载器加载ClassLoad,尽管ClassLoad被加载,但是没有被初始化,当程序调用
	 * Class的静态方法forName(“ClassLoad”)显示的初始化ClassLoad时,才是对ClassLoad的主动使用,
	 * 将导致ClassLoad被初始化,他的静态代码块被执行。
	 * @param args
	 * @throws ClassNotFoundException 
	 */
	public static void main(String[] args) throws ClassNotFoundException {
		ClassLoader loader=ClassLoader.getSystemClassLoader();
		Class objClass=loader.loadClass("com.easyway.commons.ispace.dev.lang.classloader.ClassLoad");
		System.out.println("after loader ClassLoad ");
		System.out.println("before init ClassLoad ");
		objClass=Class.forName("com.easyway.commons.ispace.dev.lang.classloader.ClassLoad");
		
	}

}

 

 

 

package com;

/**
 * 对于静态变量、静态初始化块、变量、初始化块、构造器,它们的初始化顺序依次是
 * (静态变量、静态初始化块)>(变量、初始化块)>构造器。
 * 运行以上代码,我们会得到如下的输出结果:
 *   1、静态变量
 *   2、静态初始化块 
 *   3、变量
 *   4、初始化块 
 *   5、构造器
 * 
 * @author longgangbai
 * 
 * 
 */
public class InitialOrderTest {

	// 静态变量
	public static String staticField = "静态变量";
	// 变量
	public String field = "变量";

	// 静态初始化块
	static {
		System.out.println(staticField);
		System.out.println("静态初始化块");
	}

	// 初始化块
	{
		System.out.println(field);
		System.out.println("初始化块");
	}

	// 构造器
	public InitialOrderTest() {
		System.out.println("构造器");
	}

	public static void main(String[] args) {
		new InitialOrderTest();
	}
}

 

 

package com;

/**
 * 运行一下上面的代码,结果马上呈现在我们的眼前:
 * 
 * 1、父类--静态变量 
 * 2、父类--静态初始化块 
 * 
 * 3、子类--静态变量 
 * 4、子类--静态初始化块 
 * 
 * 5、父类--变量 
 * 6、父类--初始化块 
 * 7、父类--构造器
 * 
 * 8、子类--变量 
 * 9、子类--初始化块 
 * 10、子类--构造器
 * 
 * 现在,结果已经不言自明了。大家可能会注意到一点,那就是,并不是父类完全初始化完毕后才进行子类的初始化,
 * 实际上子类的静态变量和静态初始化块的初始化是在父类的变量、初始化块和构造器初始化之前就完成了。
 * 
 * @author longgangbai
 * 
 */
class Parent {
	// 静态变量
	public static String p_StaticField = "父类--静态变量";
	// 变量
	public String p_Field = "父类--变量";

	// 静态初始化块
	static {
		System.out.println(p_StaticField);
		System.out.println("父类--静态初始化块");
	}

	// 初始化块
	{
		System.out.println(p_Field);
		System.out.println("父类--初始化块");
	}

	// 构造器
	public Parent() {
		System.out.println("父类--构造器");
	}
}

public class SubClass extends Parent {
	// 静态变量
	public static String s_StaticField = "子类--静态变量";
	// 变量
	public String s_Field = "子类--变量";
	// 静态初始化块
	static {
		System.out.println(s_StaticField);
		System.out.println("子类--静态初始化块");
	}
	// 初始化块
	{
		System.out.println(s_Field);
		System.out.println("子类--初始化块");
	}

	// 构造器
	public SubClass() {
		System.out.println("子类--构造器");
	}

	// 程序入口
	public static void main(String[] args) {
		new SubClass();
	}
}

 

分享到:
评论

相关推荐

    Java语言编码规范.pdf

    其次,关于实例变量的初始化部分可能会讲解,实例变量可以声明时直接初始化,也可以在构造函数中初始化,甚至可以在声明后的任何时间点通过实例方法进行初始化。实例变量拥有默认值,但良好的编程习惯是不要依赖于...

    双缓冲绘图技术实例讲解

    1. 初始化双缓冲:创建一个与屏幕大小相同的位图作为后台缓冲区。 2. 绘制:在后台缓冲区上执行所有的绘图操作,包括背景、对象等。 3. 更新屏幕:在合适的时机,比如窗口重绘或滚动事件发生时,将后台缓冲区的内容...

    解析Java虚拟机中类的初始化及加载器的父委托机制

    类的初始化时机则分为主动使用和被动使用。主动使用包括: 1. 创建类的实例。 2. 访问类的静态变量或对其进行赋值。 3. 调用类的静态方法。 4. 使用反射`Class.forName`。 5. 初始化子类。 6. JVM启动时作为启动类的...

    C++ Initialization Story

    接着,它将涵盖类的构造函数和成员初始化列表,讨论如何在创建对象时正确地初始化数据成员。此外,书中的内容还会涉及静态与动态内存分配的初始化,包括栈上的变量和堆上的对象。 深入到C++11及其后续标准,书里会...

    java类加载机制.xmind

    该文件是JVM中关于类加载机制的知识整理的思维导图,包括类加载机制概述、类加载的生命周期、加载时机、加载过程、类加载、类的初始化和实例化等几个大方面进行了讲解,其中类加载中还对JVM三种预定义类加载器进行了...

    java类的讲解.pdf

    }`是Point类的一个方法,用于初始化点的坐标。方法名可以与成员变量同名,但作用域不同,方法内的局部变量只在其定义的代码块内有效,而成员变量在整个类中有效。 类还可以包含构造方法(constructor),这是具有...

    单例模式讲解

    这里的关键在于`m_instance`成员变量的初始化是在类加载时完成的,因此无论何时调用`getInstance`方法都会返回同一个实例。 #### 五、登记式单例详解 登记式单例是一种更高级的单例模式,它可以管理多个单例类。...

    spring基础实例源码

    此外,还涉及了bean的生命周期状态,如单例bean的实例化时机以及原型bean的每次请求都会创建新实例等。 2. **Spring_0700_IOC_Collections**: 在这个主题中,我们探讨了如何在Spring配置中处理集合类型属性,如...

    实例讲解Ruby使用设计模式中的装饰器模式的方法

    如果 你希望改变一个已经初始化的对象的行为,你怎么办?或者,你希望继承许多类的行为,改怎么办?前一个,只能在于运行时完成,后者显然时可能的,但是可能会导致产生大量的不同的类—可怕的事情。 问题  

    Think in java读书笔记

    首先,任何静态成员和对象会在首次创建类的实例或首次访问类的静态成员时初始化,这个过程只发生一次。随后,非静态成员和对象按照它们在类中的声明顺序初始化,最后执行构建器,完成整个对象的初始化过程。 例如,...

    Android视频实时采集和播放实例

    - 初始化Camera实例和预览显示的SurfaceView。 - 设置预览回调,处理每一帧数据,可能包括编码和发送到服务器等操作。 - 创建MediaPlayer对象,设置视频源,准备并开始播放。 四、额外注意事项 1. 权限请求:确保...

    C++入门教程视频-7

    这一部分讲解了对象在创建时如何使用初始化列表来初始化成员变量,以确保它们在构造函数执行之前具有正确的初始值。初始化列表可以避免不必要的默认构造和赋值操作,提高代码效率。 2. **18 类和对象-封装-访问...

    STM32F1教学实例4 串口通信

    3. USART初始化:通过调用USART_Init()函数,设定波特率、数据帧格式、校验位和停止位。例如,设置为9600bps,8N1(无校验,1个停止位)。 4. 串口使能:最后,调用USART_Cmd(USART1, ENABLE)使能串口。 发送数据:...

    【IT十八掌徐培成】Java基础第04天-05.构造代码块-构造函数-javabean-pojo.zip

    构造代码块通常用于初始化对象的成员变量,它的执行时机早于任何方法和构造函数。这样的设计允许我们在不创建额外构造函数的情况下,为所有实例提供统一的初始化步骤。构造代码块的语法如下: ```java { // 初始化...

    WINCE下dll实例

    本文将深入探讨在WinCE下如何创建、使用及调试DLL,并结合VSC++2005开发环境进行实例讲解。 1. **DLL的基础概念** - DLL是包含可由多个程序同时使用的函数和数据的库。 - 它们在运行时被加载到进程的地址空间,而...

    C++学习课件PPT

    通过C++学习课件,你可以系统地学习以上这些知识点,并通过实例练习加深理解。这些课件通常会包含详细的讲解、示例代码、习题和解答,帮助你在实践中掌握C++编程技能。无论你是初学者还是希望提升编程能力的开发者,...

    ue4 SlateUI讲解

    这为开发者提供了一个良好的时机去初始化特定的玩家相关资源或设置。 #### 二、SlateUI基本知识 ##### 2.1 创建项目 Slate 是虚幻引擎中用于构建用户界面的框架。创建一个带有Slate UI的新项目时,首先需要确保你...

    单例模式.ppt

    通过一个静态内部类持有单例实例,内部类的加载时机延迟到第一次调用`getInstance()`时,实现了懒加载,同时也保证了线程安全,因为类加载是线程安全的。这种方式避免了同步开销,但增加了类加载的复杂性。 5. **...

    singleton-demo.zip

    静态内部类保证了类加载的时机,从而确保单例的唯一性,线程安全且延迟初始化。 ```java public class Singleton { private Singleton() {} private static class SingletonHolder { private static final ...

Global site tag (gtag.js) - Google Analytics