先来一张 JVM 中的内存模型 。

在Java 虚拟机原理这本书中介绍了类会被初始化的 5 种情况 。

1 遇到 new getstatic putstatic 和 invokestatic 这 4 条指令时,这4 条指定分别对应使用 new 关键字创建对象,读取和设置一个静态字段(被 final 修饰的静态字段除外,因为已经在编译期间把结果放到常量池中了)和调用一个类的静态方法 。

2 对类进行反射调用时 。

3 当其父类没有被初始化时,要初始化父类 。

4 当虚拟机启动时,用户需要指定一个包含 main 方法的类,虚拟机会优先初始化这个类。

5 当使用JDK1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果 REF_getStatic、REF_putStatic、REF_invokeStatic 的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。

对照着这些再来看一下我们经常混淆的类中结构的加载顺序 ,可能会有更加深刻的认识 。

关于类中结构的加载顺序 ,首次创建对象时 ,类中的静态方法 / 静态字段首次被访问时 ,Java 解释器必须先查找类路径 ,以定位.class 文件;然后载入 .class (这将创建一个 Class 对象) ,有关静态初始化的所有动作都会执行 。因此 ,静态初始化只在 Class 对象首次加载的时候进行一次 。当用 new 创建对象时 ,首先在堆上为对象分配足够的存储空间 。然后将堆中的属性分别赋上默认的初始值 。为属性显示赋值(如果有的话) 。最后执行构造器 。

综上我们可以得出这样的结论 ,类的加载顺序整体上为 “ 父类静态—》子类静态—》父类非静态—》父类构造器—》子类非静态—》子类构造 。”

下面说一些看似类被初始化 ,其实并没有的情况 。

A 通过子类应用父类静态字段 ,不会导致子类初始化 。

public class SuperClass {
static {
System.out.println("SuperClass Init !!!");
}
public static int value = 123;
} public class SubClass extends SuperClass{
static {
System.out.println("SubClass Init !!!");
}
} public class Test {
public static void main(String[] args) {
System.out.println(SubClass.value);
}
} //SuperClass Init !!!
//

B 通过数组定义来引用类 ,不会触发此类的初始化 。( 左右拖动屏幕查看代码 )

public class Test{
public static void main(String[] args) {
//System.out.println(SubClass.value);
SuperClass[] superClasses = new SuperClass[10];
}
}

运行结果并没有打印出 ”SuperClass Init !!!” ,这里并没有触发 SuperClass 类的初始化 。这里触发了另一个名为 “ [Lcom.sun.jojo.noinitclass.SuperClass ” 的类的初始化 ,他是虚拟机自动创建的直接继承于 java.lang.Object 的子类 ,创建动作由字节码指令 newarray 触发 。

C 常量在编译期间就会调入类的常量池中 ,所以直接引用变量的类并没有被初始化 。( 左右拖动屏幕查看代码 )

public class ConstClass {
static {
System.out.println("ConstClass Init !!!");
}
public static final int value = 123;
} public class Test{
public static void main(String[] args) {
//System.out.println(SubClass.value);
//SuperClass[] superClasses = new SuperClass[10];
System.out.println(ConstClass.value);
}
}
// 123 PS. ConstClass Init !!! 并没有打印

接口的初始化和类的初始化类似 ,区别在于 5 种情况的第三种 :子类的初始化过程中其父类必须先初始化 ,但接口初始化时不要求其父接口也进行初始化 ,只有在用到父接口时 ,才会去初始化 。

Java 中类的初始化过程的更多相关文章

  1. 【软件构造】-<笔记>-浅谈java中类的初始化过程

    编写java程序时,每创建一个新的对象,都会对对象的内容进行初始化. 每一个类的方法中的局部变量都有严格的初始化要求,因此假如写出下面的程序: void f(){ int i; i++; } 编译时就 ...

  2. 一道题反映Java的类初始化过程

    Java的类初始化过程: 1. 父类的static成员变量,static语句块. 2. 子类的static成员变量,static语句块. 3. 父类的普通成员变量,构造函数. 4. 子类的普通成员变量 ...

  3. java代码的初始化过程研究

        刚刚在ITeye上看到一篇关于java代码初始化的文章,看到代码我试着推理了下结果,虽然是大学时代学的知识了,没想到还能做对.(看来自己大学时掌握的基础还算不错,(*^__^*) 嘻嘻……)但 ...

  4. java中类的初始化和对象的初始化

    静态的属于全局静态区,这个部分独立存在,不管是成员还是块,都是静态的,大家地位相等,先到先得. 然后是成员初始化,这个部分在类的构造函数前初始化,因为编译器(或者设计者)可能认为构造函数调用了这个成员 ...

  5. Java类的初始化过程及清理

    一.类的数据成员初始化 Java中类的数据成员初试化可能有两种形式. 在定义类成员变量的地方直接提供初始化值(这是C++中不允许的) 在构造器中初试化.(Java中不存在类似C++中的初始化列表) 两 ...

  6. Java中类的初始化

    类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载.验证.准备.解析.初始化.使用和卸载七个阶段.其中验证.准备.解析3个部分统称为连接.类加载的过程包括了加载.验证.准备.解 ...

  7. JAVA对象的初始化过程

    出处:http://blog.csdn.net/andrew323/article/details/4665379 下面我们通过两个例题来说明对象的实例化过程. 例1:   编译并运行该程序会有以下输 ...

  8. Java中对象初始化过程

    Java为对象初始化提供了多种选项. 当new一个对象的时候,对象初始化开始: 1.首先,JVM加载类(只加载一次,所以,即使多次new对象,下面的代码也只会在第一次new的时候执行一次),此时, 静 ...

  9. Java的对象初始化过程

    成员变量(字段)初始化顺序 在一个类里初始化的顺序是由成员变量在类里面的定义的顺序来决定的.即使成员变量大量散布于类的各个方法定义的中间,那些成员变量仍会在调用任何方法之前得以初始化,甚至在构造函数调 ...

随机推荐

  1. 实验九 Web安全基础

  2. CVE-2017-12149JBoss 反序列化漏洞利用

    CVE-2017-12149 漏洞描述 互联网爆出JBOSSApplication Server反序列化命令执行漏洞(CVE-2017-12149),远程攻击者利用漏洞可在未经任何身份验证的服务器主机 ...

  3. Tomcat与Spring中的事件机制详解

    最近在看tomcat源码,源码中出现了大量事件消息,可以说整个tomcat的启动流程都可以通过事件派发机制串起来,研究透了tomcat的各种事件消息,基本上对tomcat的启动流程也就有了一个整体的认 ...

  4. es6解构、中括号前加分号

    在写项目的时候,为了方便使用了下对象的解构,无奈又遇到一坑. 为什么会不能解构呢?因为这里的{}会导致歧义,因为 JavaScript 引擎会将{xxxxx}理解成一个代码块,从而发生语法错误.只有不 ...

  5. ASP防XSS代码

    原作是在GitHub上,基于Node.js所写.但是..ASP的JS引擎跟V8又有些不同..于是,嗯.. <% Function AntiXSS_VbsTrim(s) AntiXSS_VbsTr ...

  6. hibernate的枚举注解@Enumerated

    @Enumerated(value=EnumType.ORDINAL)采用枚举类型的序号值与数据库进行交互, 此时数据库的数据类型需要是数值类型,例如在实际操作中 CatTest ct = new C ...

  7. Python基础:内置函数

    本文基于Python 3.6.5的标准库文档编写,罗列了英文文档中介绍的所有内建函数,并对其用法进行了简要介绍. 下图来自Python官网:展示了所有的内置函数,共计68个(14*4+12),大家可以 ...

  8. Python函数:对变量赋值,变量即局部

    b = 6 def f2(a): print(a) print(b) b = 9 UnboundLocalError: local variable 'b' referenced before ass ...

  9. python网络编程--线程event

    一:线程event作用 Python提供了Event对象用于线程间通信,它是线程设置的信号标志,如果信号标志位真,则其他线程等待直到信号结束. Event对象实现了简单的线程通信机制,它提供了设置信号 ...

  10. jersey HTTP Status 400 - Bad Request

    原因是jersey 内置的转换器,只能做简单的类型转换如: 首先客户端提交上来的一定是String; String ----> String/Long/Boolean 这些基本的 可以转换,但是 ...