jvm类加载
来源:互联网 发布:java算法题 编辑:程序博客网 时间:2024/04/30 16:33
导火索
在ide下创建了一个工程,写了一个main1方法,main1方法里面的类去调用maven导入a.jar,启动运行的时候报ClassNotFoundException,一开始还以为a.jar需要依赖其它类,没有导入进来,最后发现a.jar由maven管理,其依赖的jar包也都相应的导入进来了,那问题来了,什么原因导致ClassNotFoundException。经过查看异常堆栈后发现a.jar包里面有个类调用了Class.forName(“org.eclipse.jetty.alpn.ALPN”, true, null),这里拋错。这个问题引起了深思,ide跑main方法时候,是怎么加载本类和依赖的类,如果该类没有依赖的类但是也在classpath目录下面,jvm会不会去加载呢。带着这个问题,在这个工程下,再另外写了一个main2方法,运行该方法,并且打开jdk下面的jvisualvm.exe查看该进程到底创建了哪些类,最后发现它并没有去加载main1方法的类和其它没有依赖的类,如图:
结论
ide负责java编译成class文件,会去检查显示依赖的类,如果没有找到依赖会在编译的时候报错,main方法启动只加载rt.jar包下面的类、还有java扩展包的类、加本身的类,运行的时候还会去加载依赖的的类,但是其它在classpath下面的类它不会去加载。
理论基石:
一.Java中的所有类,必须被装载到jvm中才能运行,这个装载工作是由jvm中的类装载器完成的,类装载器所做的工作实质是把类文件从硬盘读取到内存中
二.java中的类大致分为三种:系统类 、扩展类 、由程序员自定义的类
三.类装载方式,有两种
1.隐式装载, 程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中
2.显式装载, 通过class.forname()等方法,显式加载需要的类
隐式加载与显式加载的区别?两者本质是一样?
四.类加载的动态性体现
一个应用程序总是由n多个类组成,Java程序启动时,并不是一次把所有的类全部加载后再运行,它总是先把保证程序运行的基础类一次性加载到jvm中,其它类等到jvm用到的时候再加载,这样的好处是节省了内存的开销,因为java最早就是为嵌入式系统而设计的,内存宝贵,这是一种可以理解的机制,而用到时再加载这也是java动态性的一种体现
五.java类装载器
Java中的类装载器实质上也是类,功能是把类载入jvm中,值得注意的是jvm的类装载器并不是一个,而是三个,层次结构如下: Bootstrap Loader - 负责加载系统类 | - - ExtClassLoader - 负责加载扩展类 | - - AppClassLoader - 负责加载应用类
为什么要有三个类加载器,一方面是分工,各自负责各自的区块,另一方面为了实现委托模型
六. 类加载器之间是如何协调工作的
前面说了,java中有三个类加载器,问题就来了,碰到一个类需要加载时,它们之间是如何协调工作的,即java是如何区分一个类该由哪个类加载器来完成呢。
在这里java采用了委托模型机制,这个机制简单来讲,就是“类装载器有载入类的需求时,会先请示其Parent使用其搜索路径帮忙载入,如果Parent 找不到,那么才由自己依照自己的搜索路径搜索类”,注意喔,这句话具有递归性
下面举一个例子来说明,为了更好的理解,先弄清楚几行代码:
public class Test { public static void main(String[] arg) { ClassLoader c = Test.class.getClassLoader(); //获取Test类的类加载器 System.out.println(c); ClassLoader c1 = c.getParent(); //获取c这个类加载器的父类加载器 System.out.println(c1); ClassLoader c2 = c1.getParent();//获取c1这个类加载器的父类加载器 System.out.println(c2); }}
运行结果:
sun.misc.Launcher
null
可以看出Test是由AppClassLoader加载器加载的
AppClassLoader的Parent 加载器是 ExtClassLoader 但是ExtClassLoader的Parent为 null 是怎么回事呵,如果留意的话,前面有提到Bootstrap Loader是用C++语言写的,依java的观点来看,逻辑上并不存在Bootstrap Loader的类实体,所以在java程序代码里试图打印出其内容时,我们就会看到输出为null
类装载器ClassLoader(一个抽象类)描述一下JVM加载class文件的原理机制
类装载器就是寻找类或接口字节码文件进行解析并构造JVM内部对象表示的组件,在java中类装载器把一个类装入JVM,经过以下步骤:
1、装载:查找和导入Class文件
2、链接:其中解析步骤是可以选择的
(a)检查:检查载入的class文件数据的正确性
(b)准备:给类的静态变量分配存储空间
(c)解析:将符号引用转成直接引用
3、初始化:对静态变量,静态代码块执行初始化工作
类装载工作由ClassLoder和其子类负责。
JVM在运行时会产生三个ClassLoader:根装载器,ExtClassLoader(扩展类装载器)和AppClassLoader
其中根装载器不是ClassLoader的子类,由C++编写,因此在java中看不到他,负责装载JRE的核心类库,如JRE目录下的rt.jar,charsets.jar等。
ExtClassLoader是ClassLoder的子类,负责装载JRE扩展目录ext下的jar类包;
AppClassLoader负责装载classpath路径下的类包,这三个类装载器存在父子层级关系,即根装载器是ExtClassLoader的父装载器,ExtClassLoader是AppClassLoader的父装载器。默认情况下使用AppClassLoader装载应用程序的类
Java装载类使用“全盘负责委托机制”。
“全盘负责”是指当一个ClassLoder装载一个类时,除非显示的使用另外一个ClassLoder,该类所依赖及引用的类也由这个ClassLoder载入;
“委托机制”是指先委托父类装载器寻找目标类,只有在找不到的情况下才从自己的类路径中查找并装载目标类。这一点是从安全方面考虑的,试想如果一个人写了一个恶意的基础类(如java.lang.String)并加载到JVM将会引起严重的后果,但有了全盘负责制,java.lang.String永远是由根装载器来装载,避免以上情况发生
除了JVM默认的三个ClassLoder以外,第三方可以编写自己的类装载器,以实现一些特殊的需求。类文件被装载解析后,在JVM中都有一个对应的java.lang.Class对象,提供了类结构信息的描述。数组,枚举及基本数据类型,甚至void都拥有对应的Class对象。Class类没有public的构造方法,Class对象是在装载类时由JVM通过调用类装载器中的defineClass()方法自动构造的
七.常见class异常
ClassNotFoundException发生在装入阶段。
当应用程序试图通过类的字符串名称,使用常规的三种方法装入类,但却找不到指定名称的类定义时就抛出该异常。
NoClassDefFoundError: 当目前执行的类已经编译,但是找不到它的定义时
也就是说你如果编译了一个类B,在类A中调用,编译完成以后,你又删除掉B,运行A的时候那么就会出现这个错误
加载时从外存储器找不到需要的class就出现ClassNotFoundException
连接时从内存找不到需要的class就出现NoClassDefFoundError
大概这样的吧,JDK API里面的解释
1.NoClassDefFoundError
当 Java 虚拟机或 ClassLoader 实例试图在类的定义中加载(作为通常方法调用的一部分或者作为使用 new 表达式创建的新实例的一部分),但无法找到该类的定义时,抛出此异常。
当前执行的类被编译时,所搜索的类定义存在,但无法再找到该定义。
2.ClassNotFoundException
当应用程序试图使用以下方法通过字符串名加载类时,抛出该异常:
* Class 类中的 forName 方法。
* ClassLoader 类中的 findSystemClass 方法。
* ClassLoader 类中的 loadClass 方法。
- 【JVM】JVM类加载机制
- JVM类加载1-加载
- jvm类加载过程
- JVM类加载
- JVM 类加载过程
- jvm :类加载原理
- JVM加载类详情
- JVM类加载器
- JVM类加载器
- JVM类加载,详谈
- JVM加载类原理
- jvm类加载机制
- JVM类加载机制
- JVM-类加载机制
- JVM类加载机制
- JVM类加载机制
- jvm 类加载器
- JVM 类加载过程
- 基于Davenport风速谱两点时程模拟
- linux命令-date显示或设置时间
- MySQL基础讲解
- utf8_bin跟utf8_general_ci的区别
- Android性能优化笔记
- jvm类加载
- 【Qt开发】QTableWidget的详细设置
- 第2周项目2-程序的多文件组织
- 【LeetCode-119】 Pascal's Triangle II(C++)
- 日常笔记-AsyncTask onPostExecute方法无法运行但不报错情况。
- SqlServer 凭据
- mysql中如何统计某字段里某个字符的个数?
- js 数字相加
- bootstrap关闭modal后,如何清空modal里的bootstrapValidator的校验痕迹