ClassLoader

Android解析ClassLoader(二)Android中的ClassLoader 相关文章 Java虚拟机系列 Android系统启动系列 Android解析ClassLoader系列 前言 在上一篇文章我们学习了Java的ClassLoader,很多同学会把Java和Android的ClassLoader搞混,甚至会认为Android中的ClassLoader和Java中的ClassLoader是一样的,这显然是不对的。这一篇文章我们就来学习Android中的C... 阅读详情

ClassLoader

类加载器

类加载的机制的层次结构

每个编写的”.java”拓展名类文件都存储着需要执行的程序逻辑,这些”.java”文件经过Java编译器编译成拓展名为”.class”的文件,”.class”文件中保存着Java代码经转换后的虚拟机指令,当需要使用某个类时,虚拟机将会加载它的”.class”文件,并创建对应的class对象,将class文件加载到虚拟机的内存,这个过程称为类加载,这里我们需要了解一下类加载的过程,如下:

Jvm执行class文件

步骤一、类加载机制

将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口,这个过程需要类加载器参与。

当系统运行时,类加载器将.class文件的二进制数据从外部存储器(如光盘,硬盘)调入内存中,CPU再从内存中读取指令和数据进行运算,并将运算结果存入内存中。内存在该过程中充当着"二传手"的作用,通俗的讲,如果没有内存,类加载器从外部存储设备调入.class文件二进制数据直接给CPU处理,而由于CPU的处理速度远远大于调入数据的速度,容易造成数据的脱节,所以需要内存起缓冲作用。

类将.class文件加载至运行时的方法区后,会在堆中创建一个Java.lang.Class对象,用来封装类位于方法区内的数据结构,该Class对象是在加载类的过程中创建的,每个类都对应有一个Class类型的对象,Class类的构造方法是私有的,只有JVM能够创建。因此Class对象是反射的入口,使用该对象就可以获得目标类所关联的.class文件中具体的数据结构。

 

 

 

类加载的最终产物就是位于堆中的Class对象(注意不是目标类对象),该对象封装了类在方法区中的数据结构,并且向用户提供了访问方法区数据结构的接口,即Java反射的接口。

 

 

步骤二、连接过程

将java类的二进制代码合并到JVM的运行状态之中的过程

验证:确保加载的类信息符合JVM规范,没有安全方面的问题

准备:正式为类变量(static变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配

解析:虚拟机常量池的符号引用替换为字节引用过程

步骤三、初始化

初始化阶段是执行类构造器<clinit>()方法的过程。类构造器<clinit>()方法是由编译器自动收藏类中的所有类变量的赋值动作和静态语句块(static块)中的语句合并产生,代码从上往下执行。

当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化

虚拟机会保、、、证一个类的<clinit>()方法在多线程环境中被正确加锁和同步

当范围一个Java类的静态域时,只有真正声名这个域的类才会被初始化

 

 

类加载器的层次结构

 

启动(Bootstrap)类加载器

扩展(Extension)类加载器

系统(-)类加载器

 

启动(Bootstrap)类加载器

启动类加载器主要加载的是JVM自身需要的类,这个类加载使用C++语言实现的,是虚拟机自身的一部分,它负责将 <JAVA_HOME>/lib路径下的核心类库或-Xbootclasspath参数指定的路径下的jar包加载到内存中,注意必由于虚拟机是按照文件名识别加载jar包的,如rt.jar,如果文件名不被虚拟机识别,即使把jar包丢到lib目录下也是没有作用的(出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类)。

扩展(Extension)类加载器

扩展类加载器是指Sun公司(已被Oracle收购)实现的sun.misc.Launcher$ExtClassLoader类,由Java语言实现的,是Launcher的静态内部类,它负责加载<JAVA_HOME>/lib/ext目录下或者由系统变量-Djava.ext.dir指定位路径中的类库,开发者可以直接使用标准扩展类加载器。

系统(System)类加载器、

也称应用程序加载器是指 Sun公司实现的sun.misc.Launcher$AppClassLoader。它负责加载系统类路径java -classpath或-D java.class.path 指定路径下的类库,也就是我们经常用到的classpath路径,开发者可以直接使用系统类加载器,一般情况下该类加载是程序中默认的类加载器,通过ClassLoader#getSystemClassLoader()方法可以获取到该类加载器。

  在Java的日常应用程序开发中,类的加载几乎是由上述3种类加载器相互配合执行的,在必要时,我们还可以自定义类加载器,需要注意的是,Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象,而且加载某个类的class文件时,Java虚拟机采用的是双亲委派模式即把请求交由父类处理,它一种任务委派模式,下面我们进一步了解它。

理解双亲委派模式

采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。可能你会想,如果我们在classpath路径下自定义一个名为java.lang.SingleInterge类(该类是胡编的)呢?该类并不存在java.lang中,经过双亲委托模式,传递到启动类加载器中,由于父类加载器路径下并没有该类,所以不会加载,将反向委托给子类加载器加载,最终会通过系统类加载器加载该类。但是这样做是不允许,因为java.lang是核心API包,需要访问权限,强制加载将会报出如下异常

java.lang.SecurityException: Prohibited package name: java.lang

 

所以无论如何都无法加载成功的。下面我们从代码层面了解几个Java中定义的类加载器及其双亲委派模式的实现,它们类图关系如下

 

双亲委派模式是在Java 1.2后引入的,其工作原理的是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式,即每个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己想办法去完成,这不就是传说中的实力坑爹啊?那么采用这种模式有啥用呢?

双亲委派模式优势

采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。可能你会想,如果我们在classpath路径下自定义一个名为java.lang.SingleInterge类(该类是胡编的)呢?该类并不存在java.lang中,经过双亲委托模式,传递到启动类加载器中,由于父类加载器路径下并没有该类,所以不会加载,将反向委托给子类加载器加载,最终会通过系统类加载器加载该类。但是这样做是不允许,因为java.lang是核心API包,需要访问权限,强制加载将会报出如下异常

类加载器间的关系

我们进一步了解类加载器间的关系(并非指继承关系),主要可以分为以下4点

启动类加载器,由C++实现,没有父类。

拓展类加载器(ExtClassLoader),由Java语言实现,父类加载器为null

系统类加载器(AppClassLoader),由Java语言实现,父类加载器为ExtClassLoader

自定义类加载器,父类加载器肯定为AppClassLoader。

类加载器常用方法

loadClass(String)

该方法加载指定名称(包括包名)的二进制类型,该方法在JDK1.2之后不再建议用户重写但用户可以直接调用该方法,loadClass()方法是ClassLoader类自己实现的,该方法中的逻辑就是双亲委派模式的实现,其源码如下,loadClass(String name, boolean resolve)是一个重载方法,resolve参数代表是否生成class对象的同时进行解析相关操作。

正如loadClass方法所展示的,当类加载请求到来时,先从缓存中查找该类对象,如果存在直接返回,如果不存在则交给该类加载去的父加载器去加载,倘若没有父加载则交给顶级启动类加载器去加载,最后倘若仍没有找到,则使用findClass()方法去加载(关于findClass()稍后会进一步介绍)。从loadClass实现也可以知道如果不想重新定义加载类的规则,也没有复杂的逻辑,只想在运行时加载自己指定的类,那么我们可以直接使用this.getClass().getClassLoder.loadClass("className"),这样就可以直接调用ClassLoader的loadClass方法获取到class对象。

findClass(String)

在JDK1.2之前,在自定义类加载时,总会去继承ClassLoader类并重写loadClass方法,从而实现自定义的类加载类,但是在JDK1.2之后已不再建议用户去覆盖loadClass()方法,而是建议把自定义的类加载逻辑写在findClass()方法中,从前面的分析可知,findClass()方法是在loadClass()方法中被调用的,当loadClass()方法中父加载器加载失败后,则会调用自己的findClass()方法来完成类加载,这样就可以保证自定义的类加载器也符合双亲委托模式。需要注意的是ClassLoader类中并没有实现findClass()方法的具体代码逻辑,取而代之的是抛出ClassNotFoundException异常,同时应该知道的是findClass方法通常是和defineClass方法一起使用的(稍后会分析)

defineClass(byte[] b, int off, int len)

defineClass()方法是用来将byte字节流解析成JVM能够识别的Class对象(ClassLoader中已实现该方法逻辑),通过这个方法不仅能够通过class文件实例化class对象,也可以通过其他方式实例化class对象,如通过网络接收一个类的字节码,然后转换为byte字节流创建对应的Class对象,defineClass()方法通常与findClass()方法一起使用,一般情况下,在自定义类加载器时,会直接覆盖ClassLoader的findClass()方法并编写加载规则,取得要加载类的字节码后转换成流,然后调用defineClass()方法生成类的Class对象

resolveClass(Class≺?≻ c)

使用该方法可以使用类的Class对象创建完成也同时被解析。前面我们说链接阶段主要是对字节码进行验证,为类变量分配内存并设置初始值同时将字节码文件中的符号引用转换为直接引用。

 

Bootstrap 底层是C++  识别系统的rt.jar包 加载核心的类   

任何类加载器先交给父类进行加载,如果父类加载失败,再交给子类执行

代码解释双亲委派模式:

没有用原生JDK的String

 

包名和类名字:

我们这么定义String类代码:

package java.lang;

public class String {
  public String toString(){
      return toString();
  }
}

 

使用测试:

package com.toov5.jvm;

public class TestJvm01 {
   public static void main(String[] args) {
     String aString = "a";
     System.out.println(aString);
}
  
}

结果:

包名类名都一样

 我们看下它的ClassLoader

package com.toov5.test;

public class Test01 {


       public static void main(String[] args) {
         String aString = "a";
         System.out.println(aString);
         System.out.println(Test01.class.getClassLoader());
         System.out.println(aString.getClass().getClassLoader());
      
    }    
}

Test01是Application 

String是 Bootstrap

 先去让父类去执行加载的 

 

 

JDK源码之ClassLoader Java 中,自定义类加载器允许从标准的 classpath 之外的位置,如特定的目录、网络或者加密文件动态加载类。自定义类加载器的核心在于理解 Java 的双亲委派模型。该模型规定:当一个类加载器收到加载请求时,它首先不会自己尝试去加载,而是将这个请求委托给父类加载器去完成。只有当所有父类加载器都无法完成加载时,当前加载器才会调用自己的 findClass 方法。因此,实现自定义类加载器的标准做法是继承类,并重写 findClass 方法。 阅读详情

相关推荐

ClassLoader加载类的原理

ClassLoader使用的是双亲委托模型来搜索类的,每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系),虚拟机内置的类加载器(Bootstrap ClassLoader)本身没有父类加载器,但可以用作其它ClassLoader实例的的父类加载器。

Willdas博客 917

Lombok源码

Jar包里面的类,只能通过这个影子类加载器才能加载到这些类,避免被其他工具或插件识别加载。看处理函数,就是一些注解的判断啊,然后对不同的注解位置做不同的方法注入啊这些。影子类加载器,继承了普通的类加载器,然后添加了自己的类加载规则。函数的逻辑都是围绕着类加载相关的东西,关键在于这个。里面是某些类的名单,用来保证名单里面的类只加载一次。里面的内容是这样的,每一行是一个类的全限定名。的包,里面全是相关注解的处理类,这应该是。Jar中的一个类,貌似是用来做补丁的。指定的是加载的类文件的后缀。

qq_31856061的博客 2015

Android中ClassLoader源码解析之真的是你认为的ClassLoader

1.前言 首先,阅读本文章之前,需要了解java中的ClassLoader的基本原理,包括java中的三级ClassLoader机制以及ClassLoader的委托机制,否则下面的内容会不知道在讲什么。虽然Android中的ClassLoader也是遵循其委托机制,但是他没有遵循java的三级ClassLoader机制,而是自己造了一个,修改了java系统的代码,如果将两者混淆的话,在Andro

ScheduledThreadPoolExecutor原理源码解析 4252

动态代理(Proxy)

对于动态代理黑马程序员给了一个很好的例子就是,你如果找一个明星唱歌你不可能直接找到她本人,你需要首先找到该明星的代理人然后把准备工作都做完 再找到明星唱歌。回到第一段的例子,如果要测量每个方法的花费时间,可以让每个方法有一个代理人实现测量方法,然后方法体本身自己实现自身的方法。比如如果要统计每个方法花费的时间,如果在每个方法中都都加入该测量方法,在一个工程中该工作量太大了,可以通过动态代理来实现。4.在测试类中声明一个实体类,然后通过代理工具类来声明代理 最后通过代理调用方法。

2302_76735364的博客 195

NE564锁相环FM解调电路设计:10.7MHz中频实测与3种失真优化方案

本文详细解析了NE564锁相环在10.7MHz中频FM解调电路中的设计与优化方案。通过分析锁相环技术基础、电路架构设计及典型失真问题,提供了3种有效的失真优化方法,包括限幅增强、VCO频偏补偿和环路滤波优化,显著提升解调性能。文章还涵盖了PCB布局要点和系统测试验证,为高频电子线路设计提供实用参考。

weixin_33314040的博客 350

Linux 桌面虚拟化技术 KVM

Linux 桌面虚拟化技术 KVM

高飞的博客 36万+

Javassist: Java Bytecode Engineering Made Simple

 翻译:ithuriel xiaoSummaryJavassist是一个执行字节码操作的强而有力的驱动代码库。它允许开发者自由的在一个已经编译好的类中添加新的方法,或者是修改已有的方法。但是,和其他的类似库不同的是,Javassist并不要求开发者对字节码方面具有多么深入的了解,同样的,它也允许开发者忽略被修改的类本身的细节和结构。字节码驱动通常被用来执行对于已经编译好的类的修改,或者

allan1031的专栏 1015

Codesys电子凸轮功能块MC_CamIn的masteroffset和slaveoffset参数的使用

问题1:在Codesys使用作轴电子凸轮时,MC_CamTableSelect的参数设置为MasterAbsolute=1,SlaveAbsolute=1,此设置为绝得模式, 此时主从轴当前位置都不为零时,此时Masteroffset=0、slaveOffset=0,凸轮启时出现突变,实轴无法启动。问题分析:在觉得模式下,主轴位置和从轴为是对应凸轮表的相位的,Masteroffset=0、slaveOffset=0,启动点时在主轴位置=0,从轴位置=0的点启动,此时主轴当前位置不为零则主从轴位置发生突变,

weixin_43587371的博客 1801

【Java 基础篇】Java类加载器详解

Java允许开发人员自定义类加载器,以满足特定的加载需求。自定义类加载器必须继承类,并重写findClass方法。在findClass方法中,开发人员可以根据自己的规则和逻辑来加载类的字节码。// 根据名称加载类的字节码 byte [ ] byteCode = loadClassByteCode(name);// 调用defineClass方法将字节码转换为Class对象 return defineClass(name , byteCode , 0 , byteCode . length);

繁依Fanyi的博客 1万+

【车间调度】车间调度问题的分类

本系列为自己学习调度相关知识的记录,如有误请指出,也欢迎调度方向的小伙伴加我好友共同交流。 车间调度问题的分类 根据工件和车间构成不同,车间调度问题可分为以下几种 1.单机调度问题 在单机调度问题(S,SMP)中,加工系统只有一台机床,待加工的工件有且仅有一道工序,所有工件都在该机床上进行加工。此问题是最简单的调度问题,当生产车间出现瓶颈机床时的调度就可视为此调度问题。 ...

weixin_51656605的博客 7430

Multisim14.0仿真(五十九)基于74LS161的24进制计数器应用设计

它具有同步预置、异步清零功能,支持并行数据加载,并可在计数使能控制下进行二进制计数。:低电平时,在下一个时钟上升沿加载输入数据(A, B, C, D)。(多个 74LS161D 串联构成 8 位、12 位等更长计数器)。低电平时,下一个时钟上升沿加载输入数据(A, B, C, D)。:低电平有效,立即清零计数器(不受时钟控制)。均为高电平时,每个时钟上升沿计数。:两者均为高电平时,计数器才能递增。:立即清零计数器(不受时钟控制)。(通过预置初始值控制计数范围)。(计数范围:0 ~ 15,即。

corlin6688的博客 4760

Java类加载器

类加载器概述、类加载器的分类、相关的API、双亲委派机制、沙箱安全机制、自定义类加载器

scj1022的博客 3803

UG NX二次开发(C#)-读取PMI对象的名称

摘要:本文介绍了在UG NX中通过NXOpen获取PMI对象名称的方法。首先说明PMI对象初始无名称,可通过重命名或属性设置名称。然后提供C#代码示例,展示如何遍历PMI集合获取对象名称,并显示名称和类型信息。适用于需要操作PMI对象的开发人员,欢迎加入技术交流QQ群749492565。(99字)

GimiGimmy 592

Android解析ClassLoader(一)Java中的ClassLoader

系统提供的类加载器只能够加载指定目录下的jar包和Class文件,如果想要加载网络上的或者是D盘某一文件中的jar包和Class文件则需要自定义ClassLoader。定义一个自定义ClassLoade并继承抽象类ClassLoader。复写findClass方法,并在findClass方法中调用defineClass方法。下面我们就自定义一个ClassLoader用来加载位于D:\lib的Class文件。

qq_39431405的博客 708

YOLOv8改进策略【卷积层】| GnConv:一种通过门控卷积和递归设计来实现高效、可扩展、平移等变的高阶空间交互操作

HorNet: 利用递归门控卷积实现高效高阶空间交互GnConv(Recursive Gated Convolution,递归门控卷积)

Limiiiing的博客 324

9.9华为OD机试真题 新系统 - 受限任务分配 (Java/Py/C/C++/Js/Go)

华为OD机试真题 新系统【受限任务分配】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题 【受限任务分配】多语言题解。

qq_45776114的博客 731

详解JAVA ClassLoader

ClassLoader,翻译成中文就是“类加载器”。对于普通的 Java 开发者来说,可能接触得比较少,但对于框架开发者或者需要深度定制 Java 应用的开发者来说,这是一个非常重要的工具。理解 ClassLoader 的工作机制,能帮助我们更好地理解 Java 程序的运行原理,还能指导我们编写出更高效的代码。ClassLoader 的主要功能是将.class文件加载到 JVM(Java 虚拟机)中,使程序能够正常运行。不过,JVM 在启动时并不会一次性将所有的类文件加载到内存中,而是根据需要动态加载。

weixin_60669486的博客 1450

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

JVM实战:ClassLoader的原理及应用

ClassLoader(类加载器) 是 JVM(Java 虚拟机)的核心组件之一。它的核心职责只有一件事:将内存外部的 .class 字节码文件,加载到 JVM 的方法区中,并转为 java.lang.Class 对象// null= null) {Java提供了抽象类java.lang.ClassLoader,所有用户自定义的类加载器都应该继承ClassLoader类,所以我们先看一下ClassLoader的逻辑,看一下它加载类的主要逻辑我截取了3个重要的方法。

小识的博客 691

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Java classloader

本文介绍了Java类加载器的继承性和隔离性。类加载器分为四个层级:Bootstrap、Extension、System和Plugin,遵循"父委托"机制。隔离性体现在父级不能调用子级类、同级加载器不能互相调用、无法获取Bootstrap实例。文章展示了如何使用URLClassLoader加载外部jar包,并提供了自定义ClassLoader的示例代码,通过读取jar文件字节码实现类加载。最后指出规范实现应优先调用父加载器并缓存已加载类,以提升性能。

你的指尖有改变世界的力量 986

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

java classloader_Java Classloader原理分析

类的加载过程指通过一个类的全限定名来获取描述此类的二进制字节流,并将其转化为方法区的数据结构,进而生成一个java.lang.Class对象作为方法区这个类各种数据访问的入口。这个过程通过Java中的类加载器(ClassLoader)来完成。类装载器是用来把类(class)装载进JVM的。JVM规范定义了两种类型的类装载器:启动内装载器(bootstrap)和用户自定义装载器(user-defin...

weixin_29495679的博客 338

ClassLoader (一) — Android 中的 ClassLoader 体系

Android 中, DVM 或 ART虚拟机加载的是 Dex 文件,因此 Androd 中自定义了部分 ClassLoader 来实现类的加载。 Android 中的 ClassLoader 类型分为两种: 1. 系统类加载器。系统类加载器主要包括 3 种,分别是BootClassLoader 、 PathClassLoader 和 DexClassLoader。 2. 自定义加载器。

Elson的博客 2060

如何实现自定义的ClassLoader

作者:Kert    本文选自:开放系统世界——赛迪网  2002年09月23日 ClassLoader,顾名思义是用来Load Class的,即加载Java类。ClassLoader读入一个字节数组,并且经过处理返回一个JVM内部可以识别的Class实例。Java虚拟机使用一套复杂但有效的方式来进行这一个至关重要的过程处理,并且提供了许多灵活的方式供人们扩展这套机制。 为什么要使用自定义Cla

K.Y.Z@优快云 2006
上一篇: 字节码技术
下一篇: 热部署和类加载器
Art&Code
博客等级 码龄7年 77粉丝 554原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值