类在什么时候加载和初始化

标签: 加载 初始化 | 发表时间:2013-11-18 22:33 | 作者:wangjungongyan
出处:http://www.iteye.com
理解类在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理解类加载和初始化细节。以上所有就是有关类被初始化和加载的全部内容。类在什么时候加载和初始化

已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [加载 初始化] 推荐:

类在什么时候加载和初始化

- - Java - 编程语言 - ITeye博客
理解类在JVM中什么时候被加载和初始化是Java编程语言中的基础概念,正因为有了Java语言规范,我们才可以清晰的记录和解释这个问题,但是很多Java程序员仍然不知道什么时候类被加载,什么时候类被初始化,类加载和初始化好像让人很困惑,对初学者难以理解,在这篇教程中我们将看看类加载什么时候发生,类和接口是如何被初始化的,我并不会拘泥于类加载器的细节或者说类加载器的工作方式.

java类加载中不会触发初始化的被动引用

- - Java - 编程语言 - ITeye博客
我们知道,在初始化一个类时,如果它的父类没有进行初始化,那么JVM就会触发其父类的初始化动作. 但是,当我们引用类的时候,可不一定会触发其初始化,这种引用类的方式称为被动引用. 可是没有竟然没有对Child类进行初始化. 这是因为val为静态字段,只有直接定义这个字段的类才会被初始化,故通过子类来引用父类静态字段val,只会触发Father类的初始化,而不会触发Child类的初始化,so 就没有Child类的事.

Java 类初始化顺序

- - Java - 编程语言 - ITeye博客
  对于静态变量、静态初始化块、变量、初始化块、构造器,它们的初始化顺序依次是. 1.(静态变量、静态初始化块)注:这两个的初始化顺序为在类中先后出现的顺序. 2(变量、初始化块)注:这两个的初始化顺序为在类中先后出现的顺序.  我们也可以通过下面的测试代码来验证这一点:. public static String staticField = "静态变量";.

Spring 初始化2次的问题

- - 企业架构 - ITeye博客
在Spring的使用中,有时初始化一些公共类,比如数据源、常量配置等,这些方法会执行两次,导致程序执行出现异常. 一个解决方法是利用Spring的事件机制,事件机制需要实现ApplicationListener监听器,只要编写一个实现类实现该接口的onApplicationEvent方法,在方法体中初始化应用需要的初始化数据,并做防二次初始化的处理.

java 类和对象的初始化

- - Web前端 - ITeye博客
  在Java中,类装载器把java类装载到虚拟机中,经过装载,链接和初始化三个步骤来完成. 其中链接中包括 校验、准备和解析. 下面对这些概念进行解析:. 装载:查找和导入类或接口的二进制数据,常用的是根据类的路径加载,还有根据网络的地址加载. 链接:执行校验、准备和解析步骤,其中解析步骤是可以选择的;.

(总结)Linux系统初始化优化Shell脚本

- 疯癫二楞子 - 服务器运维与网站架构|Linux运维|互联网研究
PS:本Shell脚本主要用于新安装Linux服务器系统的初始化工作,具体包括关闭ipv6模块、关闭selinux、让vim显示颜色、设置系统语言编码、优化系统服务、内核参数优化等. 可以根据自己的实际情况修改,可用于生产环境. 原作者是NetSeek,本人做了部分修改. cpuspeed | crond | irqbalance | microcode_ctl | mysqld | network | nginx | php-fpm | sendmail | sshd | syslog ).

Ubuntu init系统初始化流程分析

- - 有方网-一切如此简单
  现行的Linux distros主流的有两种init方式:一种是广为流传的System V initialization,它来源于Unix并且至今仍被各种Linux distros所采用;另一种是近几年提出的Upstart方式,基于事件机制,系统的所有服务,任务都是由事件驱动的. 据我所知,采用后一种方式的目前有Ubuntu(6.10 and later),Fedora(9.10 and later),Debian(optional).

java中一个对象的初始化过程

- - CSDN博客编程语言推荐文章
/* 该类演示了一个对象的初始化过程 */ class Person {. //堆内存默认初始化为null. private static String country="中国"; //静态属性,存在于方法区,随着类的加载而加载. System.out.println("静态代码块执行");. System.out.println("构造代码块执行");.

来说说Java中的实例初始化器

- - ImportNew
文首先给出个例子来探究下什么是 实例变量初始化器,什么是 实例初始化器,以及什么是 静态初始化器. 然后看看实例初始化器是怎么工作的. 先看看下面这段代码,你觉着哪部分会先被执行呢. //instance variable initializer 实例变量初始化器. //constructor 构造函数.

fastjson初始化对性能的影响(转)

- - 移动开发 - ITeye博客
       转自:http://kane-xie.iteye.com/blog/2223837.        之前在项目中序列化是用thrift,性能一般,而且需要用编译器生成新的类,在序列化和反序列化的时候感觉很繁琐,因此想转到json阵营. 对比了jackson,gson等框架之后,决定用fastjson,为什么呢,因为看名字感觉很快.