JAVA类加载和初始化

Java程序运行由java虚拟机负责。类从加载到虚拟机内存到卸载出内存,包括

加载-----链接-----初始化-----使用------卸载

链接具体包括:验证-----准备-----解析

加载:由类加载器执行,查找字节码并从这些字节码中创建一个Class对象。

链接:验证类中的字节码;为静态域分配存储内存并赋予默认值;解析这个类创建的对其他类的所有引用。

初始化:该类具有基类,则对其初始化,执行静态初始化和静态初始化块。

类初始化的时机:程序中首次使用才初始化。

首次主动使用:

1.      创建类的实例

2.      访问类的静态变量

3.      调用类的静态方法

4.      反射调用

5.      初始化类的子类,如果父类为被初始化则先初始化父类

6.      虚拟机启动时指定的启动类(包含main方法)虚拟机会先初始化该类

类的初始化步骤:

1,  没有被加载和链接的话就先进行加载连接。

2,  有直接父类并且还没有初始化那就先初始化直接父类。

3,  存在初始化语句,就按顺序依次执行初始化语句。(初始化语句包括静态语句和静态代码块)

注:

1.  如果是一个staticfinal的编译器常量,就不需要对该类进行初始化就可以被读取,但是不是编译器常量对其访问将强制进行类的初始化

class A{
	public static final int b = 10;
	public static final int c = new Random().nextInt(10);
	static {
		System.out.println("A类被初始化");
	}
}
public class Test{
	public static void main(String[] args) {
		int i = A.b;  // 不会导致初始化,因为b是一个编译时常量
		int ii = A.c; // 回导致初始化,c在编译时不能确定
	}
}

2.static域不是final的,那么访问它必须要进行链接和初始化。

3.只有当访问的静态变量或方法是在当前类或接口中定义时,才认为是对类或接口的主动使用。

interface A{
	int a = 10;
}
class AImp implements A{
	static {
		System.out.println("A类被初始化");
	}
}
public class Test{
	public static void main(String[] args) {
		int i = A.a;  // 不会导致初始化,访问的变量不是当前类中定义的
	}
}

4.使用.class创建Class的引用时,不会自动的初始化。初始化被延迟到了对静态方法或者静态域的首次调用时才执行。

class A{
	public static int b = 10;
	static {
		System.out.println("A类被初始化");
	}
}
public class Test{
	public static void main(String[] args) {

		Class class1 = A.class;  // 没有输出
		int aa = A.b; //  这句会导致输出  A类被初始化
			try {
				Class class2 = Class.forName("A");  //注释掉上面两句  output: A类被初始化
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
	}
}

类中成员的初始化

1.为类中变量赋初值在Java里面可以在定义类成员的地方为其赋值(c++里不能这样),也可以通过构造函数进行初始化,并且构造函无法阻止自动初始化也进行。

class Test{
int a;
Test(){a = 10;}// <span style="font-family: Arial, Helvetica, sans-serif;">a首先被置为0,然后变成7.</span>
}

2.变量的初始化顺序取决于变量定义的顺序。他们在任何方法(包括构造函数)调用之前得到初始化。

class A{
	public int i = 10;
	public A(){
		System.out.println("构造函数->" + i);
		i = 20;
		System.out.println("构造函数->" + i);
	}
	static {
		System.out.println("A类被初始化");
	}
}
public class Test{
	public static void main(String[] args) {
		A a = new A();  // 执行构造函数之前就饿比赋值成10了,执行构造函数后又被置为20
		// 		output :
		//		A类被初始化
		//		构造函数10
		//		构造函数20
	}
}

3.静态数据的初始化,只占有一份内存区域。静态初始化只有在必要的时刻才会进行。必要的时刻指的是类被主动使用时。

4.初始化顺序是先静态后非静态。前面讨论初始化过程只说静态语句和静态代码块,其实也会有非静态成员属性的初始化,并且是先初始化静态再初始化非静态的。不可能存在非静态成员初始化了而静态成员未被初始化的情况。

一个奇怪的问题

class  Singleton{
//	private static Singleton singleton = new Singleton();  // 1
	public static int counter1;
	public static int counter2 = 0;
	private Singleton(){
		counter1++;
		counter2++;
	}
	private static Singleton singleton = new Singleton();  // 2
	public static Singleton getInstance(){
		return singleton;
	}
}

public class Test{
	public static void main(String[] args) {
		Singleton singleton = Singleton.getInstance();
		System.out.println("counter1 = " + singleton.counter1);
		System.out.println("counter2 = " + singleton.counter2);
	}
}

输出:

放在位置1

1 Singleton singleton =Singleton.getInstance();由于是调用该类的静态方法,因为检查还未加载,接下来会依次加载,链接,初始化。

2 在链接的准备过程中singleton 为null  counter1为0 counter2为0

3 在初始化过程,按顺序初始化

3.1 初始化 private staticSingleton singleton = new Singleton();会执行构造函数,counter1为1,counter2为1

3.2 初始化public static intcounter1; 其实没有初始化的值,因此还是之前的值为1

3.3 初始化public static intcounter2 = 0; 将0赋值给counter2为0

输出为 1 和 0

counter1 = 1

counter2 = 0

放在位置2就很容易理解

counter1 = 1

counter2 = 1

时间: 2024-12-14 23:59:28

JAVA类加载和初始化的相关文章

【转载】Java系列笔记(1) - Java 类加载与初始化

Java系列笔记(1) - Java 类加载与初始化 原文地址:http://www.cnblogs.com/zhguang/p/3154584.html 目录 类加载器 动态加载 链接 初始化 示例 类加载器 在了解Java的机制之前,需要先了解类在JVM(Java虚拟机)中是如何加载的,这对后面理解java其它机制将有重要作用. 每个类编译后产生一个Class对象,存储在.class文件中,JVM使用类加载器(Class Loader)来加载类的字节码文件(.class),类加载器实质上是一

java类加载与初始化

第一段: class A{ public A(){ this.list(); } public void list(){ System.out.println("in a list.."); } } class B extends A{ private final static B instance  = new B(); //这里会调用list,是在还没构造结束的时候就调用了,但这里不会错 public static B getInstance(){ System.out.print

Java系列笔记(1) - Java 类加载与初始化

目录 类加载器 动态加载 链接 初始化 示例 类加载器 在了解Java的机制之前,需要先了解类在JVM(Java虚拟机)中是如何加载的,这对后面理解java其它机制将有重要作用. 每个类编译后产生一个Class对象,存储在.class文件中,JVM使用类加载器(Class Loader)来加载类的字节码文件(.class),类加载器实质上是一条类加载器链,一般的,我们只会用到一个原生的类加载器,它只加载Java API等可信类,通常只是在本地磁盘中加载,这些类一般就够我们使用了.如果我们需要从远

Java 类加载与初始化

文章转自 http://www.cnblogs.com/zhguang/p/3257367.html, 该文章中的类加载概念与<java编程思想>概念有所不同.<java编程思想>里类加载包含了该文章的类加载,链接,验证,初始化等过程.请读者注意. 目录 类加载器 动态加载 链接 初始化 示例 类加载器 在了解Java的机制之前,需要先了解类在JVM(Java虚拟机)中是如何加载的,这对后面理解java其它机制将有重要作用. 每个类编译后产生一个Class对象,存储在.class文

【转载】Java 类加载与初始化

原文地址:http://www.cnblogs.com/zhguang/p/3154584.html 目录 类加载器 动态加载 链接 初始化 示例 类加载器 在了解Java的机制之前,需要先了解类在JVM(Java虚拟机)中是如何加载的,这对后面理解java其它机制将有重要作用. 每个类编译后产生一个Class对象,存储在.class文件中,JVM使用类加载器(Class Loader)来加载类的字节码文件(.class),类加载器实质上是一条类加载器链,一般的,我们只会用到一个原生的类加载器,

Java实例变量初始化

由一道面试题所想到的--Java实例变量初始化 时间:2015-10-07 16:08:38      阅读:23      评论:0      收藏:0      [点我收藏+] 该题目源自微信公众号(程序员的那些事)的推送:携程 Java 工程师的一道面向对象面试题 题目是这样的:求下面程序的输出: public class Base { private String baseName = "base"; public Base() { callName(); } public v

Java类加载及变量初始化过程

Java虚拟机如何把编译好的.class文件加载到虚拟机里面?加载之后如何初始化类?静态类变量和实例类变量的初始化过程是否相同,分别是如何初始化的呢?这篇文章就是解决上面3个问题的. 本文前面理论部分比较枯燥,但是如果耐心读完,结合后面的实例,我相信你以后绝对不会再遇到java类初始化这样的疑惑.若有不正之处,请多多谅解并欢迎各位能够给予批评指正,提前谢谢各位. 1. Java虚拟机加载.class过程 虚拟机把Class文件加载到内存,然后进行校验,解析和初始化,最终形成java类型,这就是虚

java类加载和对象初始化

对象初始化过程:  1.首先,初始化父类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化:  2.然后,初始化子类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化:  3.其次,初始化父类的普通成员变量和代码块,在执行父类的构造方法: 4.最后,初始化子类的普通成员变量和代码块,在执行子类的构造方法: Java类加载机制 1.概述 Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数,属性

第16篇-JAVA 类加载与反射

第16篇-JAVA 类加载与反射 每篇一句 :敢于弯曲,是为了更坚定的站立 初学心得: 追求远中的欢声笑语,追求远中的结伴同行 (笔者:JEEP/711)[JAVA笔记 | 时间:2017-05-12| JAVA 类加载与反射 ] 1.类加载 类加载器负责将 .class 文件(可能在磁盘上, 也可能在网络上) 加载到内存中, 并为之生成对应的 java.lang.Class 对象 当程序主动使用某个类时,如果该类还未被加载到内存中,系统会通过加载.连接.初始化三个步骤来对该类进行初始化,如果没