对象创建过程之二(类加载器)

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

JAVA为我们提供了两种动态加载机制。
第一种是隐式机制。其实new一个对象和调用类的静态方法时,就是隐式机制在工作。
第二种是显示机制。显示的机制又有两种策略
第一种是用public static Class<?> forName(String className)。public static Class<?> forName(String name, boolean initialize, ClassLoader loader),第二种是用java.lang.ClassLoader的loadClass())。

Java程序启动时,并不是一次把所有的类全部加载后再运行,它总是先把保证程序运行的基础类一次性加载到jvm中,其它类等到jvm用到的时候再加载。
其中类加载过程:
1、寻找 jre 目录,寻找jvm.dll,并初始化JVM;
2、产生一个Bootstrap Loader(启动类加载器,用C++实现),在java虚拟机启动的时候会利用这个类加载器来加载  JDK安装目录下的  /JRE/LIB/rt.jar等文件。  通过System.getProperty("sun.boot.class.path")可以查询。
3、Bootstrap Loader自动加载Extended Loader(标准扩展类加载器 ,用java实现),并将其父Loader设为Bootstrap Loader。这个ClassLoader是用来加载java的扩展API的,加载JDK安装目录下的/JRE/LIB/ext目录中的类。可以通过System.getProperty("java.ext.dirs")进行查询。
也可以指定搜索路径: java -Djava.ext.dirs=d:/projects/testproj/classes HelloWorld
4、Bootstrap Loader自动加载AppClass Loader(系统类加载器 用java实现),并将其父Loader设为Extended Loader。这个ClassLoader是用来加载用户机器上CLASSPATH设置目录中的Class的。通过System.getProperty("java.class.path")可以查询。也可以覆盖环境变量: java -cp ./lavasoft/classes HelloWorld
5、最后由AppClass Loader加载HelloWorld类。
以上就是类加载的最一般的过程。
ExtClassLoader和AppClassLoader在JVM启动后,会在JVM中保存一份,并且在程序运行中无法改变其搜索路径。如果想在运行时从其他搜索路径加载类,就要产生新的类加载器。

在JAVA中,一个类用其完全匹配类名(fully qualified class name)作为标识,这里指的完全匹配类名是包名和类名。不过在JVM中一个类是用其全名再附加上一个加载类ClassLoader的实例作为唯一标识。

同一个ClassLoader加载的类文件,只有一个Class实例。 
但是,如果同一个类文件被不同的ClassLoader载入,则会有两份不同的ClassLoader实例(前提是着两个类加载器不能用相同的父类加载器)
双亲委托模式:在任何一个自定义ClassLoader加载一个类之前,它都会先委托它的父亲ClassLoader进行加载,只有当父亲ClassLoader无法加载成功后,才会由自己加载。
《特例是线程上下文类加载器,使用线程上下文类加载器, 可以在执行线程中, 抛弃双亲委派加载链模式, 使用线程上下文里的类加载器加载类.
典型的例子有, 通过线程上下文来加载第三方库jndi实现, 而不依赖于双亲委派. 大部分java app服务器(jboss, tomcat..)也是采用contextClassLoader来处理web服务。
以 Apache Tomcat 来说,每个 Web 应用都有一个对应的类加载器实例。该类加载器也使用代理模式,所不同的是它是首先尝试去加载某个类,如果找不到再代理给父类加载器。这与一般类加载器的顺 序是相反的。这是 Java Servlet 规范中的推荐做法,其目的是使得 Web 应用自己的类的优先级高于 Web 容器提供的类。
这种代理模式的一个例外是:Java 核心库的类是不在查找范围之内的。这也是为了保证 Java 核心库的类型安全。 》

在JVM加载类的时候,需要经过三个步骤,装载、连接、初始化。装载就是找到相应的class文件,读入JVM,初始化就不用说了,最主要就说说连接。
forName加载的时候就会将Class进行解释和初始化。forName也有另外一个版本的方法,可以设置是否初始化以及设置ClassLoader,在此就不多讲了。 loadClass加载类实际上就是加载的时候并不对该类进行解释,因此也不会初始化该类。
 

加载过程中会先检查类是否被已加载,检查顺序是自底向上,而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类。
卸载重载:一个已经加载的类是无法被更新的,如果你试图用同一个ClassLoader再次加载同一个类,就会得到异常(java.lang.LinkageError: duplicate classdefinition),我们只能够重新创建一个新的ClassLoader实例来再次加载新类。至于原来已经加载的类,开发人员不必去管它,因为它可能还有实例正在被使用,只要相关的实例都被内存回收了,那么JVM就会在适当的时候把不会再使用的类卸载。

真正完成类的加载工作是通过调用 defineClass来实现的;而启动类的加载过程是通过调用 loadClass来实现的。前者称为一个类的定义加载器(defining loader),后者称为初始加载器(initiating loader)。在 Java 虚拟机判断两个类是否相同的时候,使用的是类的定义加载器。

《注意事项:如果A是由Bootstrap Loader所载入,这个时候,要加入B,先交给parent进行查询,这时parent为null,交给自己查询,自己又没有,就报错。》

 

线程上下文类加载器

线程上下文类加载器(context class loader)是从 JDK 1.2 开始引入的。类 java.lang.Thread 中的方法getContextClassLoader() 和 setContextClassLoader(ClassLoader cl) 用来获取和设置线程的上下文类加载器。如果没有通过 setContextClassLoader(ClassLoader cl) 方法进行设置的话,线程将继承其父线程的上下文类加载器。Java 应用运行的初始线程的上下文类加载器是系统类加载器。在线程中运行的代码可以通过此类加载器来加载类和资源。

 前面提到的类加载器的代理模式并不能解决 Java 应用开发中会遇到的类加载器的全部问题。Java 提供了很多服务提供者接口(Service Provider Interface,SPI),允许第三方为这些接口提供实现。常见的 SPI 有 JDBC、JCE、JNDI、JAXP 和 JBI 等。这些 SPI 的接口由 Java 核心库来提供,如 JAXP 的 SPI 接口定义包含在javax.xml.parsers 包中。这些 SPI 的实现代码很可能是作为 Java 应用所依赖的 jar 包被包含进来,可以通过类路径(CLASSPATH)来找到,如实现了 JAXP SPI 的 Apache Xerces 所包含的 jar 包。SPI 接口中的代码经常需要加载具体的实现类。如 JAXP 中的 javax.xml.parsers.DocumentBuilderFactory 类中的newInstance() 方法用来生成一个新的 DocumentBuilderFactory 的实例。这里的实例的真正的类是继承自javax.xml.parsers.DocumentBuilderFactory , 由 SPI 的实现所提供的。如在 Apache Xerces 中,实现的类是 org.apache.xerces.jaxp.DocumentBuilderFactoryImpl 。 而问题在于,SPI 的接口是 Java 核心库的一部分,是由引导类加载器来加载的;SPI 实现的 Java 类一般是由系统类加载器来加载的。引导类加载器是无法找到 SPI 的实现类的,因为它只加载 Java 的核心库。它也不能代理给系统类加载器,因为它是系统类加载器的祖先类加载器。也就是说,类加载器的代理模式无法解决这个问题。

 线程上下文类加载器正好解决了这个问题。如果不做任何的设置,Java 应用的线程的上下文类加载器默认就是系统上下文类加载器。在 SPI 接口的代码中使用线程上下文类加载器,就可以成功的加载到 SPI 实现的类。线程上下文类加载器在很多 SPI 的实现中都会用到.

转载于:https://my.oschina.net/u/1182621/blog/146145

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

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

相关文章

Python_堆栈和队列

堆栈和队列 (1)堆栈&#xff0c;新放进去的先取出 #encodingutf-8 >>> stack [3, 4, 5] >>> stack.append(6) >>> stack.append(7) >>> print (stack) [3, 4, 5, 6, 7] >>> print (stack.pop()) 7 >>> print (stack) […

智能家居 (10) ——人脸识别祥云平台编程使用(编译libcurl库支持SSL,安装SSL依赖库libssl、libcrypto)

目录说明人工智能OCR识别平台介绍人脸识别接口购买编程打通OCR后台实现人脸识别&#xff08;ubuntu上实现&#xff09;问题发现编译libcurl库支持SSL安装SSL依赖库openSSL(使用工具wget)curl库重新配置&#xff0c;编译&#xff0c;安装开启SSL后重新编译人脸识别.C文件传入图片…

srs 服务关闭命令_【经验总结】如何做到网络版工作站与服务器时间同步?

随着行业发展&#xff0c;越来越多的实验室色谱数据工作站由原来的单机版&#xff0c;升级为网络版。升级后带来的益不必多说&#xff0c;那么升级带来的困难你遇到过吗&#xff1f;快来跟小析姐一起看看牛人是如何解决问题的吧。最近公司将色谱工作站进行了升级&#xff0c;采…

oss图片尺寸调用方式_是时候来一场轰轰烈烈的OSS升级了

【摘要】伴随5G和云网部署的持续推进&#xff0c;运营商OSS升级建设都已经在不断加速。| 科 | 技 | 杂 | 谈 |中国通信行业第一自媒体【1】运营商的IT支撑系统&#xff0c;正迫切需要新一轮的调整转型。今天&#xff0c;中国移动在2020全球合作伙伴大会上宣布&#xff0c;全球最…

由C过渡到C++-入门知识点

从C语言过渡到C&#xff0c;这些知识点应该是比较重要的。 目录 第一个C程序名称空间特性coutcin 缺省参数重载提问&#xff1a;为什么C语言不支持重载而C支持 引用常引用 引用与函数返回值对于指针和引用的区别引用的底层实现两者在语法上两者在物理上两者的不同之处 内联函数…

gdb pwndbg插件安装

环境&#xff1a; gdb 9.2ubuntu 20(x64) 连接 pwndbggdb9.2gdb9.2网盘连接 密码: kaq4GDB中文教程 编译gdb 由于发行的gdb比较老&#xff0c;pwndbg建议使用高版本GDB&#xff0c;因此我们下载最新的GDB9.2 安装依赖 #apt install texinfo解压GDB,卸载自带GDB #tar -vxf…

Android--UI之DatePicker、TimePicker...

前言 这一篇博客分别讲解Android平台下&#xff0c;关于日期和时间的几个相关控件。包括DatePicker&#xff08;日期选择控件&#xff09;、TimePicker&#xff08;时间选择控件&#xff09;、DatePickerDialog&#xff08;日期选择对话框&#xff09;、TimePickerDialog&#…

递归和迭代路由_静态路由在以太网接口中的不同书写会导致路由器怎样的操作结果?...

各位小伙伴们&#xff1a;大家好&#xff01;上一节和大家分享了在不同类型的网络中应该使用什么样的静态路由配置命令&#xff1b;今天我们再来看看在常见的多路访问(MBA)网络——以太网中&#xff0c;静态路由的不同书写方式将导致路由器执行那些不同的操作。如下图&#xff…

实验报告三

学 号 201521440010 中国人民公安大学 Chinese people’ public security university 网络对抗技术 实验报告 实验三 密码破解技术 学生姓名 邱景丛 年级 2015 区队 四 指导教师 高见 信息技术与网络安全学院 2016年11月7日 实验任务总纲 2016—2017 学年 第 一 …

设计前沿:25个设计师向您展示 iOS 7 界面

我们中的许多人都对新发布的 iOS 7 用户界面有点失望。扎眼的颜色搭配&#xff0c;难看的图标和可疑的设计决策&#xff0c;导致很多的设计师在 Dribbble 和 Behance 等社交网站分享自己对 iOS 界面设计的诠释。这篇文章集合了一些伟大的想法&#xff0c;改进苹果 iOS 7 的界面…

智能家居 (11) ——树莓派摄像头捕捉人脸并识别

更多干货推荐可以去牛客网看看&#xff0c;他们现在的IT题库内容很丰富&#xff0c;属于国内做的很好的了&#xff0c;而且是课程刷题面经求职讨论区分享&#xff0c;一站式求职学习网站&#xff0c;最最最重要的里面的资源全部免费&#xff01;&#xff01;&#xff01;点击进…

centos上使用高版本gcc、g++

0x0 在centos7上gcc版本是4.85&#xff0c;在编译一些代码时需要使用g的一些新特性&#xff0c;而网上大多教程都是重新编译gcc&#xff0c;太麻烦了&#xff0c;在centos 7上默认是yum search不到高版本的gcc的 安装scl scl 是Software collections 的缩写&#xff0c;安装…

【Docker系列教程之一】docker入门

我们在理解 docker 之前&#xff0c;首先我们得先区分清楚两个概念&#xff0c;容器和虚拟机。 我们用的传统虚拟机如 VMware &#xff0c; VisualBox 之类的需要模拟整台机器包括硬件&#xff0c;每台虚拟机都需要有自己的操作系统&#xff0c;虚拟机一旦被开启&#xff0c;预…

Java基础 —— 变量,选择,循环,数组,输入与输出等

目录嵌入式学JAVAJava安卓开发环境搭建并运行HelloWorld概念引入JavaSE,EE,ME的区别JREJDK编程实操&#xff1a;从C面向过程转变变量定义与输出数组的定义与遍历(循环、控制、选择和C完全一样)函数的调用&#xff1a;类比c语言结构体的使用输入数据&#xff1a;Scanner嵌入式学…

ubuntu20 编译dpdk错误 -Werror=address-of-packed-member

0x0 在ubuntu20上编译dpdk 18.11报错&#xff0c;gcc 版本为9.3.0&#xff0c;报错如下&#xff1a; error: converting a packed ‘const struct ether_addr’ pointer (alignment 1) to a ‘unaligned_uint16_t’ {aka ‘const short unsigned int’} pointer (alignment 2…

Java 特性

Java有四大特性&#xff1a; 1.封装&#xff1a;隐藏对象的属性和实现细节&#xff0c;仅仅对外公开接口。 封装具有一下优点&#xff1a; 便于使用者正确、方便的使用系统&#xff0c;防止使用者错误修改系统属性&#xff1b;有助于建立各个系统之间的松耦合关系&#xff1b;…

MyBatis 传递多个参数

2019独角兽企业重金招聘Python工程师标准>>> 在MyBatis中可以用以下的方式来传递多个参数 1. 用java.util.Map来传递, Code 如下: public List<User> getAllUsersByUserName(String username, int start, int limit){Map<String,Object> params new H…

Linux stmac网卡代码分析----probe

probe 主要分析一下驱动的主要框架&#xff0c;必要地方细致分析下 文件位置&#xff1a; drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c 从文件的最后看起&#xff1a; module_pci_driver(stmmac_pci_driver); stmmac_pci_driver结构体如下&#xff0c;里面包含了id_…

Java面向对象(1) —— 封装

目录一、封装的概念二、类的封装以及使用三、访问修饰符四、属性封装的实现五、方法封装的实现六、UML类图七、类的构造方法与可重载八、this关键字九、static关键字十、方法重载&#xff1a;overload十一、包&#xff1a;package一、封装的概念 将字段&#xff08;C结构体中的…

linux下源码软件包的安装

我们在使用linux做服务器的时候&#xff0c;因为linux自带的软件包都有些老&#xff0c;不是最新的&#xff0c;但是有时候我们为了使用最新的软件&#xff0c;会使用最新的软件的源码来进行安装。所以我们需要用心去做了...在我们拿到一个软件的源码时&#xff0c;源码一般都是…