面试:类相关---Java、Android有哪些类加载器

news2024/11/23 11:33:12

Android类加载器与Java类加载器的对比 - 掘金

Android | 类加载器与插件化 - 简书

相关复习:

面试:热修复原理_沙漠一只雕得儿得儿的博客-CSDN博客_android 热修复原理面试

面试:类的初始化过程_沙漠一只雕得儿得儿的博客-CSDN博客

什么是类加载器?

类加载器(Class Loader):顾名思义,指的是可以加载类的工具。前面

JVM类加载机制——类的生命周期已经介绍过类加载的5个过程,即:加载、验证、准备、解析、初始化,而类加载器的任务是根据一个类的全限定名来读取此类的二进制字节流到JVM中,然后转换为一个与目标类对应的java.lang.Class对象实例,在虚拟机提供了3种类加载器,启动(Bootstrap)类加载器、扩展(Extension)类加载器、系统(System)类加载器(也称应用类加载器),下面分别介绍。

Java类加载器

BootstrapClassLoader(启动类加载器)

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

ExtensionClassLoader(扩展类加载器)

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

ApplicaitonClassLoader(也叫SystemClassLoader,应用程序类加载器)

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

工作原理

Java 类加载是一种委托机制(parent delegate),即:除了顶级启动类加载器(bootstrap classloader)之外,每个类加载器都有一个关联的上级类加载器(parent 字段)。当一个类加载器准备执行类加载时,它首先会委托给上级加载器去加载,而上级加载器可能还会继续向上委托,递归这个过程。如果上级构造器无法加载,才会返回由自己加载。

双亲委派模式作用

  • 共享功能,一些Framework层级的类一旦被顶层的ClassLoader加载过就缓存在内存里面,以后任何地方用到都不需要重新加载。
  • 隔离功能,保证java/Android核心类库的纯净和安全,防止恶意加载。( 比如string类,避免用户自己写代码冒充核心类库)

ClassLoader中几个比较重要的方法

  • loadClass(String)

该方法加载指定名称(包括包名)的二进制类型,该方法在JDK1.2之后不再建议用户重写但用户可以直接调用该方法,loadClass()方法是ClassLoader类自己实现的,该方法中的逻辑就是双亲委派模式的实现

protected Class<?> loadClass(String name, boolean resolve)
      throws ClassNotFoundException {
      synchronized (getClassLoadingLock(name)) {
          // ① 先从缓存查找该class对象,找到就不用重新加载
          Class<?> c = findLoadedClass(name);
          if (c == null) {
              long t0 = System.nanoTime();
              try {
                  if (parent != null) {
                      //②如果找不到,则委托给父类加载器去加载
                      c = parent.loadClass(name, false);
                  } else {
                  //③如果没有父类,则委托给启动加载器去加载
                      c = findBootstrapClassOrNull(name);
                  }
              } catch (ClassNotFoundException e) {
                  // ClassNotFoundException thrown if class not found
                  // from the non-null parent class loader
              }

              if (c == null) {
                  // If still not found, then invoke findClass in order
                  // ④如果都没有找到,则通过自定义实现的findClass去查找并加载
                  c = findClass(name);
              }
          }
          if (resolve) {//是否需要在加载时进行解析
          }
          return c;
      }
  }

双亲委派模式作用

  • 共享功能,一些Framework层级的类一旦被顶层的ClassLoader加载过就缓存在内存里面,以后任何地方用到都不需要重新加载。
  • 隔离功能,保证java/Android核心类库的纯净和安全,防止恶意加载。( 比如string类,避免用户自己写代码冒充核心类库)

android类加载器

JVM与android虚拟机区别

dalvik与jvm的不同:

1、jvm:执行的是class文件;dalvik:执行的是dex

2、类加载系统与jvm区别较大

3、jvm只能存在一个;dalvik可以同时存在多个dvm

4、dalvk基于寄存器,jvm基于栈(内存)

ART对比dalvik:

1、DVM使用JIT将字节码转换成机器码,效率低

2、ART采用AOT预编译技术,执行效率更快

3、ART会占用更多的安装时间和存储空间

4、预编译减少了 CPU 的使用频率,降低了能耗 JIT(Just In Time,即时编译技术) AOT(Ahead Of Time,预编译技术)

android类加载机制

Android的Dalvik/ART虚拟机虽然与标准Java的JVM虚拟机不一样,ClassLoader具体的加载细节不一样,但是工作机制是类似的, (从android sdk的ClassLoader#loadClass和jdk的ClassLoader#loadClass源码可以看出都使用了双亲委托机制)

这一节我们就来分析 Android ART 虚拟机 中的类加载器:

ClassLoader 实现类作用
BootClassLoader加载 SDK 中的类
PathClassLoader加载应用程序的类
DexClassLoader加载指定的类

下面直接来看看ClassLoader的关系:

  • BootClassLoader

BootClassLoader实例在Android系统启动的时候被创建,用于加载一些Android系统框架的类,其中就包括APP用到的一些系统类。(与Java中的BootstrapClassLoader不同,它并不是由C/C++代码实现,而是由Java实现的,BootClassLoader是ClassLoader的内部类)

  • BaseDexClassLoader

我们先来看看基类BaseDexClassLoader的构造方法

public BaseDexClassLoader(String dexPath, File optimizedDirectory,
        String librarySearchPath, ClassLoader parent) {
    super(parent);
    this.pathList = new DexPathList(this, dexPath, librarySearchPath, optimizedDirectory);
}

BaseDexClassLoader构造方法的四个参数的含义如下:

参数描述
dexPath加载 dex 文件的路径
optimizedDirectory加载 odex 文件的路径
librarySearchPath加载 so 库文件的路径
parent上级类加载器

它派生出两个子类加载器:

  • PathClassLoader: 主要用于系统和app的类加载器,其中optimizedDirectory为null, 采用默认目录/data/dalvik-cache/
  • DexClassLoader: 可以从包含classes.dex的jar或者apk中,加载类的类加载器, 可用于执行动态加载, 但必须是app私有可写目录来缓存odex文件. 能够加载系统没有安装的apk或者jar文件, 因此很多热修复和插件化方案都是采用DexClassLoader;

DexClassLoader与PathClassLoader都继承于BaseDexClassLoader,这两个类只是提供了自己的构造函数,没有额外的实现,我们对比下它们的构造函数的区别。

从源码可以看出,PathClassLoader & DexClassLoader 其实都没有重写方法,所以主要的逻辑还是在 BaseDexClassLoader。

这两个类其实只有一点不同,在 Android 9.0 之前,DexClassLoader 的构造方法需要传入第二个参数optimizedDirectory,这个路径是存放优化后的 dex 文件的路径(odex)。

不过在 Android 9.0 之后,DexClassLoader 也不需要传这个参数了。

DexClassLoader.java - Android 8.0

public DexClassLoader(String dexPath, String optimizedDirectory, String librarySearchPath, ClassLoader parent) {
    super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);
}

DexClassLoader.java - Android 9.0

public DexClassLoader(String dexPath, String optimizedDirectory, String librarySearchPath, ClassLoader parent) {
    super(dexPath, null, librarySearchPath, parent);
}

PathClassLoader.java

public PathClassLoader(String dexPath,  String librarySearchPath, ClassLoader parent) {
    super(dexPath, null, librarySearchPath, parent);

可以发现这两个类的构造函数最大的差别就是DexClassLoader提供了optimizedDirectory,而PathClassLoader则没有,optimizedDirectory正是用来存放odex文件的地方,所以可以利用DexClassLoader实现动态加载。

DexPathList

我们提到 BaseDexClassLoader 将 findClass() 的任务委派给 DexPathList 对象处理,这一节我们就来分析 DexPathList 里的处理过程。

DexFile 是 dex 文件在内存中的映射
Elment - dexFile
Element[] dexElements 一个app所有的class文件都在 dexElements里

android类加载机制总结

Android虚拟机有两个主要的类加载器DexClassLoader与PathClassLoader,它们都继承于BaseDexClassLoader,它们内部都维护了一个DexPathList的对象,DexPathList主要用来存放指明包含dex文件、native库和优化odex目录。 Dex文件采用DexFile这个类来描述,Dex的加载以及类的查找都是通过DexFile调用它的native方法来完成的。

加载插件的步骤

  • 1、创建插件的 DexClassLoader 类加载器;
  • 2、获取宿主 App 的 PathClassLoader 类加载器;
  • 3、合并两个类加载器中的 dexElements,生成新的 Element[];
  • 4、通过反射将新值赋值给宿主的 dexElements 字段。
1、宿主类加载器
ClassLoader appClassLoader = context.getClassLoader();
宿主 DexPathList
Object appPathList = pathListField.get(appClassLoader);
宿主 dexElements
Object[] appDexElements = (Object[]) dexElementsField.get(appPathList);

2、插件加载器
ClassLoader pluginClassLoader = new DexClassLoader(apkPath,
        context.getCacheDir().getAbsolutePath(),
        null,
        appClassLoader);
插件 DexPathList
Object pluginPathList = pathListField.get(pluginClassLoader);
插件 dexElements
Object[] pluginDexElements = (Object[]) dexElementsField.get(pluginPathList);

3、合并 dexElements
// Object[] obj = new Object[appDexElements.length + pluginDexElements.length]; // x

Object[] newElements = (Object[]) Array.newInstance(appDexElements.getClass().getComponentType(),
        appDexElements.length + pluginDexElements.length);
System.arraycopy(appDexElements, 0, newElements, 0, appDexElements.length);
System.arraycopy(pluginDexElements, 0, newElements, 0, pluginDexElements.length);

4、赋值
dexElementsField.set(appPathList, newElements);

android类加载器与java类加载器异同

相同:

  • Android类加载器和Java的类加载器工作机制是类似的,使用双亲委托机制

不同:

  • 加载的字节码不同 Android虚拟机运行的是dex字节码,Java虚拟机运行的class字节码。

  • 类加载器不同以及类加载器的类体系结构不同 如上面的类加载器结构图

  • BootClassLoader和Java的BootStrapClassLoader区别:Android虚拟机中BootClassLoader是ClassLoader内部类,由java代码实现而不是c++实现,是Android平台上所有ClassLoader的最终parent,这个内部类是包内可见,所以我们没法使用。 Java虚拟机中BootStrapClassLoader是由原生代码(C++)编写的,负责加载java核心类库(例如rt.jar等)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/21134.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

内置 230+ 工具,它值得被官方纳入标准库

经过了几十年的发展&#xff0c;Python 的轮子生态越来越丰富&#xff0c;例如针对网络请求有 requests&#xff0c;针对命令行开发有 typer 等等&#xff0c;这些第三方库给我们的日常开发带来了极大的便利。 今天我推荐另一个第三方库 – Boltons&#xff0c;和大多数第三方…

go语言之不必要的拷贝

其实我也是个golang开发者~~ Go语言本来就以轻量快速著称&#xff0c;一位GitHub员工却偶然发现&#xff1a; 只改变一个字符的位置&#xff0c;能把一段代码运行速度提高足足42%。 简直就像是…… 这个简单有效的技巧一经发布&#xff0c;就引来众多程序员围观。 原作者自己…

论文中常见的拟合散点验证图(R语言版)

论文中常见的拟合散点验证图&#xff08;R语言版&#xff09; 如上图所示&#xff0c;是论文中常见的validation图&#xff0c;python也能实现相似的图绘。 今天先介绍R语言版&#xff0c;python改期再介绍吧 这张图需要依次实现下列功能&#xff1a; data实测与data模拟的散…

RabbitMQ系列【11】延迟队列

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 文章目录前言1. 过期消息实现延迟队列2. 过期队列实现延迟队列3. 插件实现延迟队列3.1 安装插件3.2 代码实现3.3 测试前言 延迟队列&#xff1a;即消息进入队列后不会立即被消费&#xff0c;只有到达指…

MySQL事务隔离机制 -- 必须说透

文章目录前言一、什么是数据库事务二、事务并发带来的4类问题三、事务4种隔离级别四、Mysql演示4种隔离级别总结前言 如何控制并发是数据库领域中非常重要的问题之一&#xff0c;MySQL为了解决并发带来的问题&#xff0c;设计了事务隔离机制、锁机制、MVCC机制&#xff0c;用一…

c# 实验七 图像列表框及树形视图控件的使用

前言&#xff1a; &#x1f44f;作者简介&#xff1a;我是笑霸final&#xff0c;一名热爱技术的在校学生。 &#x1f4dd;个人主页&#xff1a;个人主页1 || 笑霸final的主页2 &#x1f4d5;系列专栏&#xff1a;《项目专栏》 &#x1f4e7;如果文章知识点有错误的地方&#xf…

[附源码]java毕业设计四六级考试管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

m基于matlab的wcdma软切换算法的研究分析和仿真

目录 1.算法概述 2.仿真效果预览 3.MATLAB部分代码预览 4.完整MATLAB程序 1.算法概述 软切换是WCDMA系统的关键技术之一&#xff0c;软切换算法和相关参数的设置直接影响着系统的容量和服务质量。通过WCDMA系统的软切换技术可以提高小区覆盖率和系统容量。所以软切换技术是…

【ASM】字节码操作 工具类与常用类 LocalVariablesSorter 类 简单介绍与使用

文章目录 1.概述2. LocalVariablesSorter#2.1 class info2.2 fields3.案例3.1 编码实现3.2 编码实现v21.概述 在上一节:【ASM】字节码操作 工具类与常用类 GeneratorAdapter 介绍 我们知道了对于GeneratorAdapter 类来说,它非常重要的一个特点:将一些visitXxx()方法封装成一…

Java面向对象详解(上)

Java面向对象详解&#xff08;上&#xff09;&#x1fa85;面向对象与面向过程的区分✨面向过程&#xff1a;✨面向对象&#xff1a;&#x1fa85;类是什么&#xff1f;&#x1fa85;对象是什么&#xff1f;&#x1fa85;类的结构&#x1fa85;类中方法&#xff1a;✨成员方法与…

实战讲解SpringBoot启动时自动加载数据库数据到内存:通过回调方法自动运行Bean(图+文+源码)

1 缘起 在补充SpringCloud网关&#xff08;Gateway&#xff09;配置白名单相关知识过程中&#xff0c; 有两种实现方案&#xff1a; &#xff08;1&#xff09;SpringBoot的启动配置文件application.yml进行配置&#xff1b; &#xff08;2&#xff09;自动加载MySQL数据库中的…

【人工智能】Mindspore框架中保存加载模型

前言 MindSpore着重提升易用性并降低AI开发者的开发门槛&#xff0c;MindSpore原生适应每个场景包括端、边缘和云&#xff0c;并能够在按需协同的基础上&#xff0c;通过实现AI算法即代码&#xff0c;使开发态变得更加友好&#xff0c;显著减少模型开发时间&#xff0c;降低模…

深度学习在图像处理中的应用学习笔记

这篇学习笔记用于记录本人在读研期间的学习内容 在刚入学不久&#xff0c;发现一个B站up主对这方面进行了一系列的整理总结&#xff0c;并上传了代码&#xff0c;并且非常成体系&#xff0c;因此本人打算跟着这位up主的步骤&#xff0c;对这方面进行学习并且做一个记录&#xf…

Vue安装并使用axios发送请求

前言 本文主要介绍的是使用在Vue项目中安装并使用axios发送请求 axios介绍 axios是一种Web数据交互方式 它是一个基于promise的网络请求库&#xff0c;作用于node.js和浏览器中&#xff0c;它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中) 本质是对原生XHRX…

NAND Flash原理

Flash 简介 Flash全名叫做Flash Memory&#xff0c;属于非易失性存储设备(Non-volatile Memory Device)&#xff0c;与此相对应的是易失性存储设备(Volatile Memory Device)。关于什么是非易失性/易失性&#xff0c;从名字中就可以看出&#xff0c;非易失性就是不容易丢失&…

BGP→→

BGP-4 提供了一套新的机制以支持无类域间路由。这些机制包括支持网络前缀的通告、取消 BGP 网络中 “ 类 ” 的概念。 BGP-4 也引入机制支持路由聚合&#xff0c;包括 AS 路径的集合。 特点 BGP属于外部或域间路由协议。BGP的主要目标是为处于不同AS中的路由器之间进行路由信…

Spring Cloud Config 配置中心

最简单的配置中心&#xff0c;就是启动一个服务作为服务方&#xff0c;之后各个需要获取配置的服务作为客户端来这个服务方获取配置。 Spring Cloud Config&#xff0c;可以用 git &#xff0c;还可以用数据库、svn、本地文件等作为存储。 1. Config Server 引入 config-ser…

Day08--自定义组件的properties属性

提纲挈领&#xff1a; 1.properties属性 我的操作&#xff1a; 1》 2》 3》输出看看效果是不是真的有接收到。 ********************************* ********************************* ********************************* ********************************* **************…

Spring 源码阅读

1. beanFactory The root interface for accessing a Spring bean container. 2. BeanFactoryPostProcessor 对bean定义进行后置处理&#xff0c;比如jdbc类读取配置的密码&#xff0c;用户名等。 3.BeanPostProcessor public interface BeanPostProcessor {Object postProce…

ctfshow--RCE极限挑战

本周ctfshow的挑战注重点为RCE&#xff0c;主要利用是&#xff1a;自增绕过RCE RCE挑战1 属于简单类型 源码 error_reporting(0); highlight_file(__FILE__); $code $_POST[code]; $code str_replace("(","括号",$code); $code str_replace(".&q…