java类加载及类初始化
1.前言
java是跨平台语言,主要是因为它的java虚拟机的存在,java有事编译语言,所以需要将编写的java文件编译成jvm可运用的class字节码文件。在java中一切皆对象。对于Java虚拟机而言,一个Java类也是一个对象。一个类在JVM中被实例化成一个对象,需要经历三个过程:加载、链接和初始化。
2.加载
通过读取字节码二进制.class文件将类加载到内存,从而达到类的从硬盘上到内存上的一个迁移,所有的class必须加载到内存才能工作。一个Java类在被加载到内存后会在Java堆中创建一个类(java.lang.Class)对象,同时JVM为每个类对象都维护一个常量池(类似于符号表)并将这个字节流代表的静态存储结构转换为方法区的运行时数据结构。
- Bootstrap ClassLoader:这个加载器不是一个Java类,而是由底层的c++实现,负责在虚拟机启动时加载Jdk核心类库以及加载后两个类加载器。
- Extension ClassLoader:是一个普通的Java类,继承自ClassLoader类,负责加载{JAVA_HOME}/jre/lib/ext/目录下的所有jar包。
- App ClassLoader:是Extension ClassLoader的子对象,负责加载应用程序classpath目录下的所有jar和class文件。
- 自定义类加载器
3.链接
(1)验证
验证是类加载的第二个阶段,这个阶段也是持续时间最长(从阶段连续性来说),这个阶段从加载开始进行,一直进行到解析阶段结束。验证是为了保证class文件中的内容是符合虚拟机规范的二进制字节流,防止通过执行一些不安全的二进制字节流而导致虚拟机奔溃。 从整体来看,类加载过程的验证阶段可以分为四个部分:文件格式验证、元数据验证、字节码验证和符号引用验证。
(2)准备
准备阶段是证实为类变量分配内存并且设置初始化值的阶段,这些变量所使用的内存都在方法区分配。这个阶段进行初始化的数据只有静态字段,并且是赋值初始化值(final修饰的字段除外),不是代码中定义的值。
public static int value = 123;在准备阶段,value在方法区分配内存,并且设置初始值0,如果value被final修饰,形如:public static final int value = 123;则该变量在准备阶段将会被赋值123,并且不会引起类的初始化过程,示例及说明见第二部分(类加载的时机)的示例。
(3)解析
解析阶段是虚拟机将符号引用转化为直接引用的过程,符号引用在之前已经介绍过了,在class文件中以形如"CONSTANT_Class_info"、"CONSTANT_Fieldref_info"、"CONSTANT_Methodref_info"格式存在。符号引用是指在class文件内部的引用指向,也就是说,在class文件内部,会对各个方法,变量进行编号,当存在方法之间的调用或变量之间的引用时,以此编号为引用,找到调用的方法和变量。直接应用就是在对方法和变量解析之后将方法和变量的地址值返回到调用方,以便在调用的时候快速直接的定位方法和变量。由于在class文件没有加入到jvm时,我们是不知道方法的具体分配位置的,所以以符号引用表示,到class加载之后,在这个运行环境中,我们是可以定位方法和变量的地址的。所以在此时做解析。
4.初始化
初始化阶段是类加载过程的最后一步,这个阶段才开始真正的执行用户定义的Java程序。在准备阶段,变量已经赋过一次系统要求的初始值,而在初始化阶段,则需要为类变量(非final修饰的类变量)和其他变量赋值,其实就是执行类的<clinit>()方法。在Java语言体系中,<clinit>()是由编译器生成的,编译器在编译阶段会自动收集类中的所有类变量的赋值动作和静态语句块(static{})中的语句合并而成的,编译器收集的顺序是由语句的顺序决定的,静态语句块只能访问到定义在静态语句块之前的变量,定义在静态语句块之后的变量,可以赋值,但是不能访问。
<clinit>()方法与类的构造方法不同,它不需要用户显示的调用,虚拟机会保证父类的<clinit>()方法先于子类的<clinit>()执行,java.lang.Object的<clinit>()方法是最先执行的。接口中不能使用用静态语句块,所以接口的<clinit>()只包含类变量,所以接口的<clinit>()方法执行时,不要求限制性父接口的<clinit>()方法。<clinit>()方法对于类和接口来说不是必须的,如果类或接口中没有定义类变量,也没有静态语句块,那么编译器将不为这个类或者接口生成<clinit>()方法,如果类或者接口中生成了<clinit>()方法,那么这个方法在执行过程中,虚拟机会保证在多线程环境下的线程安全问题。
虚拟机规范给了严格规定,有且只有以下几种情况必须立即对类进行初始化:
1、遇到new、putstatic、getstatic及invokestatic这4条字节码指令时,如果类没有初始化,则立即进行初始化,这4个命令分别代表实例化一个类、设置&读取一个静态字段(没有被final修饰)、调用类的静态方法;
2、使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有初始化;
3、当初始化一个类的时候,发现其父类没有初始化;
4、当虚拟机启动时,需用将执行启动的主类(有main()方法的那个类)进行初始化;
5、当使用动态语言时,如果一个java.lang.invoke.MethodHandle实例最终的解析结果是REF_getStatic、REF_putStatic、REF_invokeStatic句柄时,并且这个句柄对应的类没有初始化。
感谢:https://blog.csdn.net/u010942465/article/details/81709246
java类加载及类初始化的更多相关文章
- 【转】两道面试题,带你解析Java类加载机制(类初始化方法 和 对象初始化方法)
本文转自 https://www.cnblogs.com/chanshuyi/p/the_java_class_load_mechamism.html 关键语句 我们只知道有一个构造方法,但实际上Ja ...
- Java类加载和类反射回顾
今天学习Spring,突然想重新复习一下Java类加载和类反射的.巩固一下底层原理.部分参考了李刚老师的<疯狂Java讲义>和陈雄华.林开雄的<Spring3.x企业应用开发实战&g ...
- java类加载和对象初始化
对象初始化过程: 1.首先,初始化父类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化: 2.然后,初始化子类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化: 3.其次,初 ...
- JAVA基础2——类初始化相关执行顺序
类初始化相关执行顺序 几个概念说明 代码块的含义与作用 static静态代码块: 一般用于初始化类中的静态变量.比如:给静态的数组或者list变量赋初值.使用static静态代码块进行初始化与直接在定 ...
- java中的类加载器ClassLoader和类初始化
每个类编译后产生一个Class对象,存储在.class文件中,JVM使用类加载器(Class Loader)来加载类的字节码文件(.class),类加载器实质上是一条类加载器链,一般的,我们只会用到一 ...
- Java程序设计19——类的加载和反射-Part-A
1 本文概要 本章介绍Java类的加载.连接和初始化的深入知识,并重点介绍Java反射相关的内容.本章知识偏底层点,这些运行原理有助于我们更好的把我java程序的运行.而且Java类加载器除了根加载器 ...
- 一文读懂Java类加载机制
Java 类加载机制 Java 类加载机制详解. @pdai Java 类加载机制 类的生命周期 类的加载:查找并加载类的二进制数据 连接 验证:确保被加载的类的正确性 准备:为类的静态变量分配内存, ...
- ClassLoader类加载器 & Java类加载机制 & 破坏双亲委托机制
ClassLoader类加载器 Java 中的类加载器大致可以分成两类: 一类是系统提供的: 引导类加载器(Bootstrap classloader):它用来加载 Java 的核心库(如rt.jar ...
- jvm之java类加载机制和类加载器(ClassLoader),方法区结构,堆中实例对象结构的详解
一.类加载或类初始化:当程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载.连接.初始化3个步骤来对该类进行初始化.如果没有意外,JVM将会连续完成3个步骤. 二.类加载时机: 1 ...
随机推荐
- Python内置函数(11)——classmethod
英文文档: classmethod(function) Return a class method for function. A class method receives the class as ...
- 1.python简介
简介 1.python语言介绍 python的创始人:Guido Van Rossum 2.python是一门什么样的语言 编程语言主要从以下几个角度进行分类:编译型,静态型,动态性,强类型定义语言和 ...
- Java核心技术及面试指南 多线程并发部分的面试题总结以及答案
7.2.10.1有T1.T2.T3三个线程,如何保证T2在T1执行完后执行,T3在T2执行完后执行? 用join语句,在t3开始前join t2,在t2开始前join t1. 不过,这会破坏多线程的并 ...
- Django知识点
一.Django pip3 install django C:\Python35\Scripts # 创建Django工程 django-adm ...
- PHP_D4_“简易聊天室 ”的具体技术实现
上面已经介绍了系统的关键技术,下面对具体实现进行详解: 1.开发时,经常需要利用一个配置文件来存储系统的参数,例如:数据库连接信息等.这样可以提高系统的可移植性,当系统的配置发生变化时,例如:更改服务 ...
- 《HelloGitHub月刊》第 10 期
前言 这一年感谢大家的支持,小弟这里给大家拜年了! <HelloGitHub月刊>会一直做下去,欢迎大家加入进来提供更多的好的项目. 最后,祝愿大家:鸡年大吉- <HelloGitH ...
- java 文件过滤器
创建文件过滤器 MyFilter ,实现 FileFilter 接口,实现 accept() 方法: package com.test.IODemo1; import java.io.File; im ...
- RabbitMQ消息队列(十一)-如何实现高可用
在前面讲到了RabbitMQ高可用集群的搭建,但是我们知道只是集群的高可用并不能保证应用在使用消息队列时完全没有问题,例如如果应用连接的RabbitMQ集群突然宕机了,虽然这个集群时可以使用的,但是应 ...
- centos6.7 配置外网端口映射
目的: 为节省公司外网ip,现需要把部分没有外网ip的服务器做端口映射. 服务器节点: 118.192.66.66(外网服务器) em1 内网 em2 外网 192.168.32.124(内网服务器) ...
- 讲一下Asp.net core MVC2.1 里面的 ApiControllerAttribute
先贴文章链接 正文 ASP.NET Core MVC 2.1 特意为构建 HTTP API 提供了一些小特性,今天主角就是 ApiControllerAttribute. (注:文章是18年2月份的, ...