理解类在JVM中什么时候被加载和初始化是Java编程语言中的基础概念,正因为有了Java语言规范,我们才可以清晰的记录和解释这个问题,但是很多Java程序员仍然不知道什么时候类被加载,什么时候类被初始化,类加载和初始化好像让人很困惑,对初学者难以理解,在这篇教程中我们将看看类加载什么时候发生,类和接口是如何被初始化的,我并不会拘泥于类加载器的细节或者说类加载器的工作方式。仅仅使这篇文章更加专注和简结。
类什么时候加载
类的加载是通过类加载器(Classloader)完成的,它既可以是饿汉式[eagerly load](只要有其它类引用了它就加载)加载类,也可以是懒加载[lazy load](等到类初始化发生的时候才加载)。不过我相信这跟不同的JVM实现有关,然而他又是受JLS保证的(当有静态初始化需求的时候才被加载)。
类什么时候初始化
加载完类后,类的初始化就会发生,意味着它会初始化所有类静态成员,以下情况一个类被初始化:
实例通过使用new()关键字创建或者使用class.forName()反射,但它有可能导致ClassNotFoundException。
类的静态方法被调用
类的静态域被赋值
静态域被访问,而且它不是常量
在顶层类中执行assert语句
反射同样可以使类初始化,比如java.lang.reflect包下面的某些方法,JLS严格的说明:一个类不会被任何除以上之外的原因初始化。
类是如何被初始化的
现在我们知道什么时候触发类的初始化了,他精确地写在Java语言规范中。但了解清楚 域(fields,静态的还是非静态的)、块(block静态的还是非静态的)、不同类(子类和超类)和不同的接口(子接口,实现类和超接口)的初始化顺序也很重要类。事实上很多核心Java面试题和SCJP问题都是基于这些概念,下面是类初始化的一些规则:
类从顶至底的顺序初始化,所以声明在顶部的字段的早于底部的字段初始化
超类早于子类和衍生类的初始化
如果类的初始化是由于访问静态域而触发,那么只有声明静态域的类才被初始化,而不会触发超类的初始化或者子类的初始化即使静态域被子类或子接口或者它的实现类所引用。
接口初始化不会导致父接口的初始化。
静态域的初始化是在类的静态初始化期间,非静态域的初始化时在类的实例创建期间。这意味这静态域初始化在非静态域之前。
非静态域通过构造器初始化,子类在做任何初始化之前构造器会隐含地调用父类的构造器,他保证了非静态或实例变量(父类)初始化早于子类
初始化例子
这是一个有关类被初始化的例子,你可以看到哪个类被初始化
1
/**
2
* Java program to demonstrate class loading and initialization in Java.
3
*/
4
public class ClassInitializationTest {
5
6
public static void main(String args[]) throws InterruptedException {
7
8
NotUsed o = null; //this class is not used, should not be initialized
9
Child t = new Child(); //initializing sub class, should trigger super class initialization
10
System.out.println((Object)o == (Object)t);
11
}
12
}
13
14
/**
15
* Super class to demonstrate that Super class is loaded and initialized before Subclass.
16
*/
17
class Parent {
18
static { System.out.println("static block of Super class is initialized"); }
19
{System.out.println("non static blocks in super class is initialized");}
20
}
21
22
/**
23
* Java class which is not used in this program, consequently not loaded by JVM
24
*/
25
class NotUsed {
26
static { System.out.println("NotUsed Class is initialized "); }
27
}
28
29
/**
30
* Sub class of Parent, demonstrate when exactly sub class loading and initialization occurs.
31
*/
32
class Child extends Parent {
33
static { System.out.println("static block of Sub class is initialized in Java "); }
34
{System.out.println("non static blocks in sub class is initialized");}
35
}
36
37
Output:
38
static block of Super class is initialized
39
static block of Sub class is initialized in Java
40
non static blocks in super class is initialized
41
non static blocks in sub class is initialized
42
false
从上面结果可以看出:
超类初始化早于子类
静态变量或代码块初始化早于非静态块和域
没使用的类根本不会被初始化,因为他没有被使用
再来看一个例子:
1
/**
2
* Another Java program example to demonstrate class initialization and loading in Java.
3
*/
4
5
public class ClassInitializationTest {
6
7
public static void main(String args[]) throws InterruptedException {
8
9
//accessing static field of Parent through child, should only initialize Parent
10
System.out.println(Child.familyName);
11
}
12
}
13
14
class Parent {
15
//compile time constant, accessing this will not trigger class initialization
16
//protected static final String familyName = "Lawson";
17
18
protected static String familyName = "Lawson";
19
20
static { System.out.println("static block of Super class is initialized"); }
21
{System.out.println("non static blocks in super class is initialized");}
22
}
23
24
Output:
25
static block of Super class is initialized
26
Lawson
分析:
这里的初始化发生是因为有静态域被访问,而且不一个编译时常量。如果声明的”familyName”是使用final关键字修饰的编译时常量使用(就是上面的注释代码块部分)超类的初始化就不会发生。
尽管静态与被子类所引用但是也仅仅是超类被初始化
还有另外一个例子与接口相关的,JLS清晰地解释子接口的初始化不会触发父接口的初始化。强烈推荐阅读JLS14.4理解类加载和初始化细节。以上所有就是有关类被初始化和加载的全部内容。类在什么时候加载和初始化
分享到:
相关推荐
当一个类被加载、连接、初始化后,它的生命周期就开始了,当代表该类的Class对象不再被引用、即已经不可触及的时候,Class对象的生命周期结束。那么该类的方法区内的数据也会被卸载,从而结束该类的生命周期。一个类...
NULL 博文链接:https://jeckfan.iteye.com/blog/1108756
Java深度历险(二)——Java类的加载、链接和初始化
Java类加载器:静态变量初始化.docx
大家在安装完Revit或者卸载后重装Revit时是否遇到外部工具无法初始化附加模块的问题,每次打开不停的弹出对话框,烦得要死。 无法初始化附加模块“CollaborateDB”,因为程序集“C:\Program Files\Autodesk\...
对于调用费时的步骤,可以将其延后到窗体显示之后再加载。使用方法: new DelayLoading(this, new MethodInvoker(DataBind)).Execute();
JVM把class文件加载到内存,并对数据进行校验、解析和初始化,最终形成 JVM可以直接使用的Java类型的过程。 \quad·加载 \quad\quad将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时...
深入研究java加载初始化............
Java 的初始化问题和其他高级语言类似。一个明显不一样的地方是体现在它的类加 载过程。传统的编程语言包括C++等,程序是作为启动过程的一部分立刻被加载,而Java 的 类加载只在需要使用程序代码时才会被加载(每个...
解决数码视讯Q5使用USB_Burning_Tool刷机时 提示 初始化DDR/读取初始化结果/USB错误
类加载器通过这种父亲-后代的方式组织在一起,形成树状层次结构。代理模式则指的是一个类加载器既可以自己完成Java类的定义工作,也可以代理给其它的类加载器来完成。由于代理模式的存在,启动一个类的加载过程的类...
在各种浏览器中,都会对CSS的选择器默认一些数值,譬如当h1没有被设置数值时,显示一定大小。但并不是所有的浏览器都使用一样的数值,所以有了CSS Reset,以让网页的样式在各浏览器中表现一致。
主要介绍了在Spring Boot中加载初始化数据的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
要创建一个类的实例,必须加载和初始化该类。 main()方法所在的类,会被优先加载并初始化 子类初始化前,会先加载并初始化它的父类 初始化一个类,其实质上就是执行了()方法 ()方法包含了,静态变量显式赋值代码以及...
该文件是JVM中关于类加载机制的知识整理的思维导图,包括类加载机制概述、类加载的生命周期、加载时机、加载过程、类加载、类的初始化和实例化等几个大方面进行了讲解,其中类加载中还对JVM三种预定义类加载器进行了...
本附件是相关博文的示例工程,欢迎有需要的小伙伴下载。下载后使用vs2013直接可以编译测试。希望感兴趣的小伙伴能亲自动手实战。
AudioPolicy&AudioFlinger初始化总体框架初始化步骤简介初始化步骤详细流程分析1、loadConfig()2、initialize()2.1、初始音频路由引擎2.2、加载so 并且打开设备节点2.3、打开输出流 总体框架 AudioFlinger和Audio...
如果这个类存在直接父类,并且这个类还没有初始化(**在一个类加载器中,类只能被初始化一次**),那就先初始化直接父类(不适用于接口)。 3. 加入类中存在的初始化语句(如static变量和static块),那就先执行...
主要介绍了Java类加载连接和初始化原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
1、jQuery 页面加载初始化的方法有3种 ,页面在加载的时候都会执行脚本, 第一种(比较常用): 代码如下: $.function(){ alert(“第一种方法”); }); 第二种: 代码如下: $(document).ready(function(){ ...