20、java中的类加载机制

1、类加载机制是什么?

       类加载机制指的就是jvm将类的信息动态添加到内存并使用的一种机制。

2、那么类加载的具体流程是什么呢?

        一般说类加载只有三步:加载、连接和初始化,其中连接包括验证、准备和解析,用于将运行时加载的类文件添加到jre环境中使用。

                               

 

加载:加载就是将类文件读取到内存中并对类信息做了初步的处理。这里是有讲究的,jvm一启动就会先加载一些类,这些类位于jdk中的rt.jar中,而另外的类就不会加载,而是当用到时才加载,这也就是预加载和运行时加载,运行时加载时jvm会先去内存中查看是否存在要使用的类,如果没有则按着这个类的全限定名进行加载,之前在IO部分也说过,像这种文件,在内存中是以一种数据序列的形式存在,也就是加载到内存的是类文件的二进制流信息,另外就是这个二进制流可以通过多条路径获取,不一定非要读取磁盘上的文件信息。然后jvm不会闲着,他会将类中的静态信息如:类信息、静态变量、常量等添加到jvm中的方法区,一般还会在堆中创建一个Class的对象用来表示这个类的信息。

验证:对加载到内存的二进制流的信息进行合法性校验,一切为了安全。试想一下,如果叮咣叮咣的写一堆三字经到.class文件,然后加载到内存,这时候jvm一运行不崩溃才怪。

准备:这个阶段主要是对类变量进行操作,如果仅是类变量,那么会根据其类型在方法区给变量开辟空间,并附一个对应类型的默认值。如果变量除了使用static修饰外,还用final修饰,那么则给变量赋定义的值。

解析:其实这一个我也不是太理解,解析是虚拟机将常量池内的符号引用解析为直接引用。以下为自己理解,大白话描述:何为符号引用,我理解的就是使用源码中的类名、方法名、变量名等来应用内存中对应的地址域所对应的数据,而直接引用呢就是将这些名称进行解析成一个可以直接指向内存地址的变量,直接引用的数据一定在内存中已经存在了,而符号引用所对应的数据不一定存在,我自认为的就是只是声明了一个变量,没有赋值,所以有的时候他自己都不知道自己到底指向哪里。

初始化:就是根据类中的构造方法来初始化类的过程,例如:我们都知道静态变量是随着类的加载而加载的,所以这里就会给静态变量初始化一个值,而对于那些成员方法,如果在构造器中没有调用的话,他们是不会被调用的。说的通俗易懂就是初始化那些被static修饰的部分,因为随着类的加载而加载。

3、加载类的流程具体是谁实现的?

       上面一直说jvm加载类,那么如果再往细处划分又是怎么样的呢?其实jvm中有专门管着加载类的工具,这就是类加载器。类加载器主要用于根据类的全限定名将对应的class文件的流信息加载到虚拟机内存,并将其转为Class对象。类加载器有四种:

       启动类加载器(Bootstrap ClassLoader):加载\Java\jdk1.8\jre\lib 下的类

       扩展类加载器(Extension ClassLoader):加载\Java\jdk1.8\jre\lib\ext下的类

       应用程序类加载器(Application ClassLoader):加载用户路径上的类,就是开发者自定义的类

       自定义加载器:加载自定义位置的类文件,为了避免以上三个加载器都加载不到指定的包。

类加载器的主要作用是根据类的全类名将类的字节码信息添加到内存中并根据字节码信息创建一个Class对象来表示这个类信息,这里充分体现了面向对象的思想,万物皆可为对象,每一个不同类的信息的就是类的一个对象。

类加载器的基本用法:

public static void main(String[] args) throws ClassNotFoundException {// 返回系统类加载器,平时使用不多,常用当前类的加载器去获取指定的类信息//ClassLoader classLoader = ClassLoader.getSystemClassLoader();// 常用当前类的加载器去获取指定的类信息ClassLoader classLoader = SelfClassLoaderTest.class.getClassLoader();// 获取当前类的类加载器的父类加载器ClassLoader parentClassLoader = classLoader.getParent();// 根据类的全路径名获取类信息,创建一个	Class 的对象Class loadClass = classLoader.loadClass("com.czp.reflection.Student");// 加载一些配置文件可以使用这个方法InputStream inputStream = ClassLoader.getSystemResourceAsStream("文件名");
}

类加载器加载类时的源码分析:

//根据name查询对应类的Class对象,最终通过jni技术用的c、c++的方法
protected final Class<?> findLoadedClass(String name) {if (!checkName(name))return null;return findLoadedClass0(name);
}
private native final Class<?> findLoadedClass0(String name);//这个方法应该被自定义的类加载器覆盖
protected Class<?> findClass(String name) throws ClassNotFoundException {throw new ClassNotFoundException(name);
}//加载的机制是双亲委托加载
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{//先锁住synchronized (getClassLoadingLock(name)) {// 检查类是否已经加载Class<?> c = findLoadedClass(name);//如果没有加载if (c == null) {try {//判断是否有父类的加载器if (parent != null) {//有父类加载器就用父类加载器去加载c = parent.loadClass(name, false);} else {//没有父类加载器了,则就用启动类加载器去加载c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) { }//如果没有加载到对应的类信息if (c == null) {// findClass方法是一个空方法,所以这里如果使用的是自定义加载器加载类的话,就会试图通过自定义的加载器去获取对应的类信息c = findClass(name);// 定义类装入器;记录数据sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}}if (resolve) {resolveClass(c);}return c;}
}//将字节数组转换为类类的实例
protected final Class<?> defineClass(String name, byte[] b, int off, int len)  throws ClassFormatError
{protectionDomain = preDefineClass(name, protectionDomain);String source = defineClassSourceLocation(protectionDomain);Class<?> c = defineClass1(name, b, off, len, protectionDomain, source);postDefineClass(c, protectionDomain);return c;
}

如何实现一个自定义类加载器?思路呢就是先读取到.class文件,然后根据读到的数据创建一个Class的对象,正好ClassLoader中已经帮我们实现了,只是需要自定义查找文件的路径,获取到文件的字节流,然后根据提供的defineClass方法将字节转成对应Class对象即可。需要继承ClassLoader类,并重写findClass方法,实现代码如下:

public class MyClassLoader extends ClassLoader{private String path;//在哪个目录下读取.class文件public MyClassLoader(String path) {this.path = path;}@SuppressWarnings("deprecation")@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {byte []b = getClassBinaryData(name);if (b != null) {return defineClass(b, 0, b.length);//将字节数组转陈对应的Class对象} else {throw new ClassNotFoundException();}}//根据路径获取到对应的字节数组private byte[] getClassBinaryData(String className) {String classPath = path + "/" + className.replace(".", "/") +".class";byte[] bs = null;FileInputStream fis = null;ByteArrayOutputStream baos = null;try {fis = new FileInputStream(classPath);baos = new ByteArrayOutputStream();byte[] buffer = new byte[2048];int num = 0;while ((num = fis.read(buffer)) != -1) {baos.write(buffer, 0, num);}bs = baos.toByteArray();} catch (IOException e) {e.printStackTrace();} finally {try {if (fis!=null) {fis.close();}} catch (Exception e2) {}}return bs;}
}-----------------------------测试public static void main(String[] args) {MyClassLoader myClassLoader = new MyClassLoader("E:/");try {Class<?> findClass = myClassLoader.findClass("EnumTest");System.out.println(findClass);} catch (ClassNotFoundException e) {e.printStackTrace();}
}

       这就是类加载器的介绍,这个时候不知是否会有疑问,如果两个加载器要加载的类在两个加载器的路径下均有资源,这要怎么办呢?是两个都添加,然后覆盖,还是咋滴?其实类加载器加载类文件时遵循一种双亲委派模型机制,介绍如下:当一个类加载器收到类加载的请求时,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时(即ClassNotFoundException),子加载器才会尝试自己去加载,这几个加载器之间的父子关系为:启动类加载器>扩展类加载器>应用程序类加载器>自定义加载器,这里的父子关系并不指的是类上边的extends。

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

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

相关文章

nssl1447-小智的糖果【dp】

正题 题目大意 长度为nnn的序列&#xff0c;mmm个位置要求两边都比他大&#xff0c;kkk个位置要求两边都比他小。求序列个数。 解题思路 若第xxx个位置为山峰&#xff0c;那么ax−1<ax>ax1a_{x-1}<a_x>a_{x1}ax−1​<ax​>ax1​&#xff0c;我们用upiup_iu…

21、java中的反射机制

先推荐安装一个 eclipse 的反编译插件 Enhanced Class Decompiler 是什么&#xff1f; 在说反射之前先说一下编译时类型和运行时类型&#xff0c;大家都知道List是一个接口&#xff0c;它是不可以被实例化的&#xff0c;但是可以通过多态实现&#xff1a;List list new Arra…

【北京】BXUG第12期活动基于 .NET Core构建微服务和Xamarin

分享主题&#xff1a;基于 .NET Core构建微服务实战分享分享者&#xff1a;薛锋 北京切尔思科技架构师 兼任东北大学信息安全工程师和技术主播&#xff0c;行业内专注于研究 .NET Core和Web应用&#xff0c;具有比较扎实的技术基础和数年的从业经历。在GitHub上主持数个开…

2017西安交大ACM小学期数据结构 [树状数组,极大值]

Problem D 发布时间: 2017年6月28日 10:51 最后更新: 2017年6月28日 16:38 时间限制: 1000ms 内存限制: 32M 描述 给定一个长度为n的序列a1, a2, ..., an当k满足2≤k≤n−1, ak>ak−1且ak>ak1时, 将元素k称为极大值点, 给出q个操作, 操作分为两种 对于形如1xy的操作…

nssl1448-小智过马路【模拟】

正题 题目大意 nnn个横向道&#xff0c;若干辆车&#xff0c;每辆车速度恒定&#xff0c;给出方向位置长度。 过马路的速度&#xff0c;最早开始时间&#xff0c;最晚开始时间。求最长的可以通过马路的时间段。 解题思路 计算出每辆车限制的时间区间&#xff0c;然后排序找到…

22、java中的注解

注解是什么&#xff1f; 注解可以理解成注释、标记、标签的意思&#xff0c;用来标记类、方法等。就相当于现实生活中的一些事物&#xff0c;上边贴一个标签或者写一些注释性文字来描述它可以用来做什么、怎么用、何时用等信息。Java中的注解也是一样的&#xff0c;用来表示被标…

谈谈ASP.NET Core中的ResponseCaching

前言前面的博客谈的大多数都是针对数据的缓存&#xff0c;今天我们来换换口味。来谈谈在ASP.NET Core中的ResponseCaching&#xff0c;与ResponseCaching关联密切的也就是常说的HTTP缓存。在阅读本文内容之前&#xff0c;默认各位有HTTP缓存相关的基础&#xff0c;主要是Cache-…

2017西安交大ACM小学期数据结构 [树状数组 离散化]

Problem E 发布时间: 2017年6月28日 12:53 最后更新: 2017年6月29日 21:35 时间限制: 1000ms 内存限制: 64M 描述 给定一个长度为n的序列a1, a2, ..., an给定两个整数L, R输出有多少个二元组(x,y),x≤y, 满足L≤∑yixai≤R9104≤n≤105, −109≤ai≤109, −109≤L≤R≤10…

使用 dynamic 类型让 ASP.NET Core 实现 HATEOAS 结构的 RESTful API

上一篇写的是使用静态基类方法的实现步骤: 使用dynamic (ExpandoObject)的好处就是可以动态组建返回类型, 之前使用的是ViewModel, 如果想返回结果的话, 肯定需要把ViewModel所有的属性都返回, 如果属性比较多, 就有可能造成性能和灵活性等问题. 而使用ExpandoObject(dynamic)就…

23、java中的网编基础

什么是网络编程&#xff1f; 在说网络编程之前要先知道什么是网络&#xff0c;网络是一种实现资源共享和数据传输的系统。而网络编程就是使用代码编写程序来进行网络之间数据的传输。使用java进行网络之间数据的传输是比较简单的&#xff0c;java中提供了一些现成的类供我们使…

2017西安交大ACM小学期数据结构 [又是树状数组、异或]

Problem F 发布时间: 2017年6月28日 10:31 最后更新: 2017年6月29日 21:35 时间限制: 2000ms 内存限制: 64M 描述 给定一个nm的矩形, 初始时所有元素都为0给出q个操作, 操作有三种 对于形如1x的操作, 将第x行的所有元素异或1对于形如2y的操作, 将第y列的所有元素异或1对于…

P2717-寒假作业【逆序对,树状数组】

正题 题目链接:https://www.luogu.com.cn/problem/P2717 题目大意 nnn个数&#xff0c;求有多少个连续子序列的平均值大于等于kkk。 解题思路 因为长度会十分干扰&#xff0c;所以我们将所有数减去kkk。问题就变为了求有多少连续子序列的和非负。用前缀和逆序对求就好了。 co…

使用 BenchmarkDotnet 测试代码性能

先来点题外话&#xff0c;清明节前把工作辞了&#xff08;去 tm 的垃圾团队&#xff0c;各种拉帮结派、勾心斗角&#xff09;。这次找工作就得慢慢找了&#xff0c;不能急了&#xff0c;希望能找到个好团队&#xff0c;好岗位吧。顺便这段时间也算是比较闲&#xff0c;也能学习…

24、jdbc操作数据库(1)

什么是jdbc&#xff1f; 看一下官方怎么说&#xff0c;JDBC 英文名Java DataBase Connectivity&#xff0c;使用java连接数据库的工具&#xff0c;就是一组使用java代码来执行SQL语句的API。 Jdbc有什么用&#xff1f; 数据库有多种&#xff0c;并且不同数据库操作时的方式和…

jzoj3918-蛋糕【二分】

正题 题目链接:https://jzoj.net/senior/#contest/show/2953/0 题目大意 n∗mn*mn∗m的矩阵&#xff0c;有数字&#xff0c;横着三刀竖着三刀分成16份使得最小那份最大。 解题思路 暴力枚举竖着的三刀&#xff0c;然后二分答案判定即可。 codecodecode #include<cstdio&g…

2017西安交大ACM小学期数论 [阅兵式]

阅兵式 发布时间: 2017年6月25日 12:53 最后更新: 2017年7月3日 09:27 时间限制: 1000ms 内存限制: 128M 描述 阅兵式上&#xff0c;将士们排成一个整齐的方阵&#xff0c;每个将士面朝前方。问正中心的将士能向前看到几个将士&#xff1f;注意&#xff0c;一条直线上的将…

25、jdbc操作数据库(2)

说一下使用jdbc时涉及到的一些基本的接口和类 java.sql.Driver 是数据库驱动接口&#xff0c;com.mysql.jdbc.Driver是mysql对应的驱动&#xff0c;由数据库供应商实现&#xff0c;用于提供驱动&#xff0c;实现了java.sql.Driver接口。 java.sql.DriverManager 管理驱动的…

jzoj3919-志愿者【换根法,线段树,树形dp】

正题 题目链接:https://jzoj.net/senior/#main/show/3919 题目大意 nnn个点kkk个需要到达的点&#xff0c;然后求每个点出发经过这些点的最短路径。 解题思路 因为不用回去&#xff0c;答案就是以这点为根链接所有点的树减去离这个点最远点的距离。 我们用线段树维护最远点距…

2017西安交大ACM小学期数论 [水题]

水题 发布时间: 2017年6月25日 14:06 最后更新: 2017年7月3日 09:27 时间限制: 1000ms 内存限制: 128M 描述 平均因数个数的统计对于估算数论题目复杂度具有非常重要的意义。小A同学听了今天的课后&#xff0c;于是想要自己写一个程序&#xff0c;求出1到n的平均因数个数…

26、jdbc操作数据库(3)

1、结果集的元数据操作 ResultSetMetaData 是描述ResultSet的元数据对象&#xff0c;可以通过元数据对象获取结果集的列信息&#xff0c;使用方式如下&#xff1a; public void query() {Connection connection DBUtil.getConnection();String sql "SELECT ID,UNAME u,…