初始化是类加载中最后的一个阶段,也是与我们敲代码关系最大的一个阶段,所以我特意提了一个章节出来说这个问题.我想很多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"; }
运行结果为
这里需要说明的是
继承关系类之间按照什么顺序进行初始化
程序员最关心的,无非是初始化的过程中执行了哪几行代码,而哪些没有 被执行,对应的执行顺序是怎么样的.我大概总结了一下无非是如下几点
(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){ } }
最后输出
(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"); } }
输出
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; } }
输出为
(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(); } }
输出为
最后补充一点是,学校的很多老湿出题的时候老喜欢把这个类的初始化与构造函数的调用放一起出题,来做混淆.也就是说,<clinit>与<init>的混淆.. 简单一点说,就是先加载,再创建对象(或者说先<clinit>,再<init>).至于说<init>方法之间的重载之类的内容,由于本片文章里说的是类的初始化过程,并不是说创建对象的过程.所以这里就不深入说了.嘿嘿.这个可以参照我N早前整理的文章
Java方法分派
相关推荐
在Java开发中,JVM(Java虚拟机)的类加载机制是至关重要的,因为它负责将类的字节码转换为运行时的实例。本专题"性能调优专题-jvm类加载机制-performance-jvmclassloader"深入探讨了如何通过理解并优化类加载过程来...
类加载机制不仅涉及到类的加载、验证、准备、解析和初始化等步骤,还包括类加载时机的选择及类加载器的具体工作原理等内容。 #### 一、类加载时机 Java类的生命周期主要包括以下几个阶段:加载、验证、准备、解析...
### 深入研究Java类加载机制 #### 一、Java类加载机制概述 Java类加载机制是Java程序运行的第一步,它对于理解Java虚拟机(JVM)的行为至关重要。类加载过程涉及到类的加载、链接(验证、准备、解析)、初始化等...
Java的类加载机制:加载,连接,初始化。JAVA类加载器: Bootstrap ClassLoader : 根类加载器, Extension ClassLoader: 扩展类加载器, System ClassLoader : 系统类加载器, Java反射
Java 类加载器是Java虚拟机(JVM)的核心组成部分,它负责将...它涉及到类的查找、加载、初始化等过程,以及如何通过调整类加载器配置来优化应用性能和安全性。深入研究这些概念,能够让你在处理类加载问题时游刃有余。
在Java中,类的加载、验证、解析和初始化都是由ClassLoader来完成的。Tomcat作为一个Web服务器,其类加载机制设计得相当灵活,以便支持不同Web应用之间的隔离和热部署。 Tomcat的类加载机制主要由以下几部分构成: ...
本篇文章将深入探讨Android热修复框架的工作原理,特别是基于类加载机制的代码修复。 Android热修复的核心在于替换或修补运行时应用中的问题代码,而实现这一目标的关键是类加载器(ClassLoader)。在Java和Android...
总结,JVM 类加载机制是Java平台的核心特性之一,它确保了程序的稳定运行和动态扩展能力。理解类加载器的工作原理和双亲委派模型对于优化程序性能、解决类冲突以及构建复杂的模块化系统至关重要。在实际开发中,掌握...
对于数字解码器来说,初始化过程涉及到配置硬件资源、加载解码算法、设置工作参数等一系列操作。这些步骤保证了解码器能够正确识别和处理输入的数字信号,避免错误或不稳定的解码结果。 三、初始化方法 初始化数字...
实验将结合具体的Java程序实例,运用单例模式对静态变量和对象进行初始化,以此来加深对类加载机制的理解。 #### 实验环境设置 为了确保实验的顺利进行,需要搭建合适的硬件和软件环境。硬件方面,建议使用一台...
类加载机制的过程可以分为三个阶段:加载、链接和初始化。 加载阶段:在加载阶段,Java虚拟机将.class文件加载到内存中,并将其转换为机器可执行的代码。加载阶段是类加载机制的第一阶段。 链接阶段:在链接阶段,...
Java 类加载器静态变量初始化机制详解 Java 类加载器是 Java 语言的核心组件之一,负责将 Java 字节码文件加载到内存中,以便 JVM 可以执行它们。在 Java 中,类加载器是通过委派机制来实现的,即一个类加载器可以...
5. **初始化**:这是类加载的最后阶段,会执行类的初始化代码(即静态初始化块),包括静态变量的显示初始化(如赋值语句)、初始化静态字段、执行类初始化方法()等。只有当类被首次主动使用时,才会触发初始化。...
在Java编程语言中,程序初始化的顺序是一个关键概念,它涉及到类加载、对象创建以及执行流程的安排。了解这些顺序对于编写高效、无错误的代码至关重要。以下是对Java程序初始化顺序的详细说明: 1. **类加载阶段**...
类加载机制包括加载、验证、准备、解析和初始化五个阶段,确保了程序的安全性和稳定性。 1. **加载**:这是类加载的第一步,JVM会通过类加载器找到对应的`.class`文件。类加载器主要有Bootstrap ClassLoader(引导...
类加载器的父委托机制是Java类加载机制的核心特性,保证了类加载的一致性和安全性。当一个类加载器需要加载类时,它首先会委托其父加载器尝试加载,只有当父加载器无法加载时,当前加载器才会尝试加载。这样设计的...
该文件是JVM中关于类加载机制的知识整理的思维导图,包括类加载机制概述、类加载的生命周期、加载时机、加载过程、类加载、类的初始化和实例化等几个大方面进行了讲解,其中类加载中还对JVM三种预定义类加载器进行了...
动态类加载机制的实现过程主要包括三个步骤:加载、连接和初始化。在加载步骤中,Java 类加载器会根据类的名称和路径将类文件加载到内存中。在连接步骤中,Java 类加载器会对加载的类文件进行验证、准备和解析。在...
本文将深入探讨ClassLoader的工作原理和类加载机制,帮助开发者理解这个至关重要的概念。 1. 类加载机制概述 Java的类加载机制遵循“双亲委派模型”(Delegation Model)。当一个类被加载时,它首先会尝试由当前...
Java虚拟机JVM类加载初始...了解类加载机制对于优化性能、理解和解决类加载相关问题至关重要,特别是在分布式、模块化和热部署等场景下。理解这些细节可以帮助开发者更好地控制类的生命周期,提高程序的效率和稳定性。