java类的加载过程有以下几步共同完成:

加载->连接->初始化。连接又分为验证、准备、解析

  • 一个非数组类的加载阶段(加载阶段获取类的二进制字节流的动作)是可控性最强的阶段,这一步我们可以去完成还可以自定义类加载器去控制字节流的获取方式(重写一个类加载器的 loadClass() 方法)。

  • 数组类型不通过类加载器创建,它由 Java 虚拟机直接创建。
    所有的类都由类加载器加载,加载的作用就是将 .class文件加载到内存。

JVM 中内置了三个重要的 ClassLoader,除了 BootstrapClassLoader 其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader。

  1. BootstrapClassLoader(启动类加载器) :最顶层的加载类,(JNI :java本地接口)由C++实现,负责加载 %JAVA_HOME%/lib目录下的jar包和类或者或被 -Xbootclasspath参数指定的路径中的所有类。

  2. ExtensionClassLoader(扩展类加载器) :主要负责加载目录 %JRE_HOME%/lib/ext
    目录下的jar包和类,或被 java.ext.dirs 系统变量所指定的路径下的jar包。

  3. AppClassLoader(应用程序类加载器) :面向我们用户的加载器,负责加载当前应用classpath下的所有jar包和类。

双亲委派机制:

每一个类都有注解的类加载器。系统中的Classloader在协同工作的时候回默认使用双亲委派机制。再类加载的时候,系统会首先判断当前类的是否被加载过。已经被加载的类会直接返回,否则才会尝试加载。加载的时候,首先会把该请求委派给父类的加载器的loadClass()处理,因此所有的请求最终都应该传送到顶层的启动类的加载器BootstrapClassLoader。当父类加载器无法处理时,才交给自己处理,当父类加载器是null时,会使用类加载器bootstrapClassLoader作为父类加载器。

双亲委派模型实现源码分析

private final ClassLoader parent;
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 首先,检查请求的类是否已经被加载过
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {//父加载器不为空,调用父加载器loadClass()方法处理
c = parent.loadClass(name, false);
} else {//父加载器为空,使用启动类加载器 BootstrapClassLoader 加载
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
//抛出异常说明父类加载器无法完成加载请求
} if (c == null) {
long t1 = System.nanoTime();
//自己尝试加载
c = findClass(name); // this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
  • 其实这个双亲翻译的容易让别人误解,我们一般理解的双亲都是父母,这里的双亲更多地表达的是“父母这一辈”的人而已,并不是说真的有一个 Mother ClassLoader 和一个 Father ClassLoader 。另外,类加载器之间的“父子”关系也不是通过继承来体现的,是由“优先级”来决定。

双亲委派机制的好处
双亲委派模型保证了Java程序的稳定运行,可以避免类的重复加载(JVM 区分不同类的方式不仅仅根据类名,相同的类文件被不同的类加载器加载产生的是两个不同的类),也保证了 Java 的核心 API 不被篡改。如果没有使用双亲委派模型,而是每个类加载自己加载自己的话就会出现一些问题,比如我们编写一个称为 java.lang.Object 类的话,那么程序运行的时候,系统就会出现多个不同的 Object 类。
如果我们不想用双亲委派模型怎么办?
为了避免双亲委托机制,我们可以自己定义一个类加载器,然后重写 loadClass() 即可。

自定义类加载器

除了 BootstrapClassLoader 其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader。如果我们要自定义自己的类加载器,很明显需要继承 ClassLoader。

Java类的加载过程-重点!!的更多相关文章

  1. JAVA - 类的加载过程

    JAVA - 类的加载过程 JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化. 加载 加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这个类的java.lang.Class对象 ...

  2. Java类的加载过程与ClassLoader的理解及测试

    当程序准备运行某个类,但该类还未被加载到内存中时,会经过以下三个步骤进行类的加载: 类的加载(Load)→类的连接(Link)→类的初始化(Initialize) 加载:类经过javac.exe编译的 ...

  3. java类的加载过程

    1.类的加载顺序 (1)JVM在首次加载类时会对  静态初始化块.静态成员变量. 静态方法进行一次初始化. (2)只有在调用new方法时才会创建类的实例. (3)对象创建过程: 首先执行父类(如果有) ...

  4. Java 类的加载过程(阿里面试题)

    问以下程序打印出什么内容: 问题及解析如下: /** * 加载方法不等于执行方法,初始化变量则会赋值 * 类加载顺序应为 加载静态方法-初始化静态变量-执行静态代码块 * 实例化时 先加载非静态方法- ...

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

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

  6. java类从加载、连接到初始化过程

    类加载器 在了解Java的机制之前,需要先了解类在JVM(Java虚拟机)中是如何加载的,这对后面理解java其它机制将有重要作用. 每个类编译后产生一个Class对象,存储在.class文件中,JV ...

  7. java 反射,类的加载过程以及Classloader类加载器

    首先自定义一个类Person package reflection; public class Person { private String name; public int age; public ...

  8. 别翻了,这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析【JVM篇二】

    目录 1.什么是类的加载(类初始化) 2.类的生命周期 3.接口的加载过程 4.解开开篇的面试题 5.理解首次主动使用 6.类加载器 7.关于命名空间 8.JVM类加载机制 9.双亲委派模型 10.C ...

  9. Dubbo源码解析之SPI(一):扩展类的加载过程

    Dubbo是一款开源的.高性能且轻量级的Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用.智能容错和负载均衡,以及服务自动注册和发现. Dubbo最早是阿里公司内部的RPC框架,于 ...

随机推荐

  1. filebeat输出结果到elasticsearch的多个索引

    基本环境: filebeat版本:6.5.4 (Linux,x86-64) elasticsearch版本:6.54   (一)需求说明 在一台服务器上有多个日志需要使用filebeat日志收集到el ...

  2. linux 下指定配置文件安装mongodb

    下载 官网下载地址:https://www.mongodb.com/try/download/community,并上传linux 服务器 二.mongon目录结构下 /data/mongo . lo ...

  3. 零基础的Java小白如何准备初级开发的面试

    对于各位Java程序员来说,只要能有实践的机会,哪怕工资再低,公司情况再一般,只要自己上心努力,就可能在短时间内快速提升,甚至在工作2年后进大厂都有希望,因为项目里真实的开发实践环境是平时学习不能模拟 ...

  4. Python编码相关

    1.#coding=utf-8的作用 作用是这个文件代码的编码格式,如果没有声明代码中不能出现中文字符,包括注释中也不能出现.否则会报错SyntaxError: Non-ASCII character ...

  5. Mysql LIMIT的用法

    使用范围 MySQL语句中的limit字句可以帮助我们在使用执行查询的时候,返回数据库中间的数据或者是只提取前几段数据 使用语法 SELECT * FROM table LIMIT [offset,] ...

  6. k8s之深入解剖Pod(一)

    上文说了一下k8s的简单使用,接下来就让我们来具体深入了解一下Pod.为了避免篇幅太长,所以会分成几篇. 目录: Pod定义详解 静态Pod Pod容器共享Volume 一.Pod定义详解 先看一个简 ...

  7. Java 面试知识点【背诵版 240题 约7w字】

    -- 转载自牛客网 是瑶瑶公主吖 Java 基础 40 语言特性 12 Q1:Java 语言的优点? ① 平台无关性,摆脱硬件束缚,"一次编写,到处运行". ② 相对安全的内存管理 ...

  8. C# 委托、事件、表达式树理解

    1.什么是委托? 委托是一种动态调用方法的类型,属于引用型. 委托是对方法的抽象和封装.委托对象实质上代表了方法的引用(即内存地址) 所有的异步都是委托   委托就是函数当入参   委托被各种语法糖遮 ...

  9. 根据数据库反向生成PD

    原博文 http://www.360doc.com/content/14/0820/20/12385684_403420399.shtml 步骤 File___Reverse Engineer___D ...

  10. 一.C语言概述

    C语言的起源 贝尔实验室的Dennis Ritchie在1972年开发了C,当时他正与ken Thompson一起设计UNIX操作系统,然而,C并不是完全由Ritchie构想出来的.它来自Thomps ...