`
chenjingbo
  • 浏览: 456452 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

类加载机制-初始化

 
阅读更多

    初始化是类加载中最后的一个阶段,也是与我们敲代码关系最大的一个阶段,所以我特意提了一个章节出来说这个问题.我想很多2B老湿经常会拿这个来考学生,看最后打印的值是什么..一般我看到这种题目就觉得恶心,但是我这次还是决定踩这坨屎...

    初始化的部分我想分为两个部分

    (1)虚拟机什么时候会对类做初始化

    (2)继承关系类按照什么顺序进行初始化

 

虚拟机什么时候会对类做初始化

类在什么情况下被加载,虚拟机的规范中并没有明确的规定 ,但是,类的初始化却明确规定了:有且只有四种情况必须立即对类进行初始化.

(1) 遇到new ,getstatic ,putstatic ,invokestatic 这4个字节码的时候必须对类进行初始化.new 表示在代码中显示的用new关键字创建对象.getstatic 和 putstatic表示读取和设置某个类的静态字段.invokestatic 表示初始化某个类的静态方法.

(2)使用java.lang.reflect包的方法对类进行反射调用的时候,必须先初始化

(3) 初始化某个类的时候,如果其父类没有初始化,则必须先初始化父类.

(4)包含main方法的类,虚拟机会先初始化.

   

除了上面说的4中情况,其他任何情况都不会初始化类.下面可以看几个不被初始化的情况.

 

通过子类引用父类的静态字段,不会导致子类初始化

package com.taobao.initialization;

public class InitializationClass {

	public static void main(String[] args) {
		System.out.println(SubClass.str);
	}

}
class SuperClass {
	static {
		System.out.println("super class ini!");
	}
	public static String str = "str";
}
class SubClass extends SuperClass{
	static {
		System.out.println("sub class ini!");
	}
}

 运行结果为



 

通过创建对象数组,并不会类初始化

package com.taobao.initialization;

public class InitializationClass2 {

	public static void main(String[] args) {
		MyClass[] classes = new MyClass[10];
	}

}
class MyClass {
	static {
		System.out.println("my class init!");
	}
	public static String str = "str";
}

 

运行结果为 无任何输出.

 

引用其他类的常量,不会造成该类的初始化

package com.taobao.initialization;

public class InitializationClass3 {

	public static void main(String[] args) {
		System.out.println(ConstClass.str);
	}

}
class ConstClass {
	static {
		System.out.println("consts class init!");
	}
	public static final String str = "str";
}

 运行结果为



 这里需要说明的是 

写道
ConstClass类中的常量str,在编译阶段已经把此常量放到了InitializationClass3类中自己的常量池中了.也就是说,其实InitializationClass3类中并没有ConstClass类的引用了.

 

 

继承关系类之间按照什么顺序进行初始化

  

    程序员最关心的,无非是初始化的过程中执行了哪几行代码,而哪些没有 被执行,对应的执行顺序是怎么样的.我大概总结了一下无非是如下几点

(1)先静态变量赋值,然后再执行静态语句快(static语句块).正因为如此所以在static语句块中是可以访问类变量的.

(2)虚拟机保证了在子类的static语句快(或者说<clinit>)执行之前,父类的<clint>已经执行完毕.所以第一次被执行的<clinit>方法对应对应于java.lang.Object

(3)父类的<clinit>方法优先于子类的赋值操作

(4)<clinit>方法对于类或者接口来说不是必须的.一般来说如果这个类没有静态语句块,也没有对变量的赋值操作,那么就不会有<clinit>方法 

(5)<clinit>方法默认是加锁的.也就是说,如果多线程同时去初始化某个类,那么<clinit>方法是有同步状态的.前一个类没有初始化好的时候,后面的线程会等待.鉴于如此,尽量少在<clinit>方法(大部分是static{}语句块)中放耗时很多的操作.

 

下面是对应的例子

(1)

public class Foo {
    public static String str = "hello";

    static {
        //先静态变量赋值,然后再执行静态语句快(static语句块).正因为如此所以在static语句块中是可以访问类变量的.
        System.out.println(str);
    }

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

 

 最后输出

写道
hello

 (2) 

public class Foo extends Bar {
    public static String str = "hello";

    static {
        System.out.println(str);
    }

    public static void main(String [] args){

    }
}

class Bar {
    static {
        //虚拟机保证了在子类的static语句快(或者说<clinit>)执行之前,父类的<clint>已经执行完毕.
        System.out.println("bar init");
    }
}

 输出

写道
bar init
hello

(3)

public class Foo extends Bar {
    public static int F_LENGTH = LENGTH;

    static {
        System.out.println(F_LENGTH);
    }
    public static void main(String [] args){

    }
}

class Bar {
    public static int LENGTH = 2012;

    static {
        //父类的<clinit>方法优先于子类的赋值操作
        LENGTH = 2013;
    }
}

 输出为

写道
2013

 (4)这个直接看一下对应类的javap输出就OK

 (5)

public class Foo{


    static {
        //<clinit>方法默认是加锁的.也就是说,如果多线程同时去初始化某个类,那么<clinit>方法是有同步状态的.前一个类没有初始化好的时候,后面的线程会等待.
        if(true){
            System.out.println("Foo init.....";
            while (true){

            }
        }
    }
    public static void main(String [] args){
        Foo f1 = new Foo();
        Foo f2 = new Foo();
    }
}

 输出为

写道
Foo init....

 

 

    最后补充一点是,学校的很多老湿出题的时候老喜欢把这个类的初始化与构造函数的调用放一起出题,来做混淆.也就是说,<clinit>与<init>的混淆.. 简单一点说,就是先加载,再创建对象(或者说先<clinit>,再<init>).至于说<init>方法之间的重载之类的内容,由于本片文章里说的是类的初始化过程,并不是说创建对象的过程.所以这里就不深入说了.嘿嘿.这个可以参照我N早前整理的文章 

Java方法分派

 

 

分享到:
评论

相关推荐

    Java类加载机制与反射-PPT

    Java的类加载机制:加载,连接,初始化。JAVA类加载器: Bootstrap ClassLoader : 根类加载器, Extension ClassLoader: 扩展类加载器, System ClassLoader : 系统类加载器, Java反射

    java类加载机制.xmind

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

    java相关的2024面试题集锦

    - 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制 - 类加载机制采用懒加载的方式 - 遇到new、getstatic、...

    详解JAVA类加载机制(推荐)

    JAVA源码编译由三个过程组成: 1、源码编译机制。 2、类加载机制 ...系统可能在第一次使用某个类时加载该类,也可能采用预加载机制来加载某个类,当运行某个java程序时,会启动一个java虚拟机进程,两次运行

    深入理解java类加载机制

    在类加载方面,我们将深入探讨Java程序的类加载原理和流程,包括加载、验证、准备、解析和初始化等五个环节的详细解析,并对其强调点进行详细讲解。我们将详细介绍Java虚拟机中类的生命周期并探讨类加载时的各种问题...

    深入理解Java虚拟机-虚拟机类加载机制.xmind

    虚拟机把描述类的数据从Class文件中加载到内存,并对数据进行校验、转换解析和初始化,最终形成可被虚拟机直接使用的Java类型,这就是虚拟机加载机制。

    JVM 面试题总结.md

    - 请你描述一下 Java 中的类加载机制? - 加载 - 验证 - 准备 - 解析 - 初始化 - 使用 - 卸载 - 在 JVM 中,对象是如何创建的? - 内存分配方式有哪些呢? - 请你说一下对象的内存布局? - 对象头 ...

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

    解析Java虚拟机中类的初始化及加载器的父委托机制共14页.pdf.zip

    Java虚拟机类加载机制浅谈

     虚拟机将描述类的数据从Class文件加载到内存,并对数据进行校验、准备、解析和初始化,终会形成可以被虚拟机使用的Java类型,这是一个虚拟机的类加载机制。Java中的类是动态加载的,只有在运行期间使用到该类的...

    java加载机制.png

    1.java源文件是怎么编译成class文件的 2.类的生命周期 3.java类加载机制 4.类的加载 5.类的加载过程 6.类是怎么被初始化的? .....

    详解vue-router 初始化时做了什么

    最近因为业务需要,实现了一个简单的前端 router,正好也来看一下 vue router 是怎么实现的。这次先来一起看看 vue-...利用 vue 的插件机制,加载 vue-router: Vue.use(VueRouter); 实例化 VueRouter: const rout

    Java类的加载、链接和初始化

    一、Java的类加载机制回顾与总结:  我们知道一个Java类要想运行,必须由jvm将其装载到内存中才能运行,装载的目的是把Java字节代码转换成JVM中的java.lang.Class类的对象。这样Java可以对该对象进行一系列操作,...

    类加载思维导图,原理、机制等

    类加载思维导图 1、类加载器的原理 1)类缓存 2)类加载器 2、类加载机制 加载、验证、准备、解析、初始化 3、类加载的时机 主动、被动引用 4、双亲委托机制

    Java类加载机制浅析

    所谓类加载机制就是 虚拟机把Class文件加载到内存 并对数据进行校验,转换解析和初始化 形成可以虚拟机直接使用的Java类型,即java.lang.Class   1、装载(Load)  查找和导入class文件 (1)通过一个类的全限定名

    深入浅出类加载机制

    类加载机制1.1 加载1.2 验证1.3 准备1.4 解析1.5 初始化1.5.2 为什么静态方法不能调用非静态方法1.6 使用1.7 拆卸2. 类加载器2.1 类加载器种类2.1.1 Java虚拟机自带的类加载器2.1.2 用户自定义的类加载器2.2 双亲...

    CEGUI深入解析

    4.1.2 初始化和退出流程 - 82 - 4.1.3 输入系统的事件派遣流程 - 87 - 4.2 资源管理 - 96 - 4.2.1资源管理模式 - 96 - 4.2.2 图像集 - 102 - 4.3 系统接口 - 106 - 4.3.1 脚本接口 - 107 - 4.3.2 XML相关接口 - 107 ...

    类实例化顺序讲解 附阿里巴巴一道笔试题

    类实例化顺序一 概述 阿里巴巴一道笔试题二 类加载及初始化详解2.1 源码到字节码2.1.1 类结构简介2.1.2 字节码反汇编工具2.2 类加载机制2.2.1 加载2.2.2 链接2.2.3 初始化2.3 类初始化过程【重点】2.3.1 方法详解...

    关于JVM的总结

    加载-&gt;(验证-&gt;准备-&gt;解析)(连接)-&gt;初始化-&gt;使用-&gt;卸载 类被加载到虚拟机内存开始,到卸载出内存为止,生命周期包含: 加载,验证,准备,解析,初始化,使用,卸载 7个阶段,加载,验证,准备,初始化和卸载这5个...

    深入理解Java类加载.docx

    虚拟机把描述类的数据从 Class 文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的 Java 类型,这就是虚拟机的类加载机制。 在Java语言里面,类型的加载、连接和初始化过程都是在...

    【JVM】类的奇幻漂流——类加载机制探秘

    本文可以带着读者初探类加载机制。上来先放类加载各个阶段的主要任务,用于给读者一个大概的印象体验,现在记不住也没有什么关系。 现在只需要记住三个名词,装载——&gt;连接——&gt;初始化,记住了吗,我们要开始奇幻...

Global site tag (gtag.js) - Google Analytics