一、前言
一处编译,处处运行!
二、JVM是什么?
JDKJDK包含了JRE,JRE是java程序的运行环境;
JDK:java开发工具包,既包含了JRE,也包含一些编译器等开发工具,例如javac、javap命令;
JRE:java程序运行环境;
JVM:属于JRE中;
通过合理设置jvm内存空间,保障jvm的正常运行;
三、类的加载三问
1) 什么是类的加载?
通过一个类的全限定名(包名与类名)来获取定义此类的二进制字节流(Class文件),读入到内存,将其放在运行时数据区的方法区内,然后在堆区创建一个 java.lang.class 对象,用来封装类在方法区内的数据结构。
2)什么时候加载?
通常情况,都是在这个类被调用的时候,被加载出来,但是jvm都有预加载机制,它能预料到哪个类即将被使用,就会去预加载这个类,如果在预先加载过程中遇到了.class文件缺失或存在错误,类加载器必须主动使报告错误,如果这个类一直不被使用,它也就不会被加载。
3)从哪里加载?
a、从本地系统中直接加载
b、通过.class文件
c、从zip、jar等归档文件中加载.class文件
d、从专有数据库中提取.class文件
e、将java源代码编译为.class文件
四、类加载器(class-loader)
启动类加载器(Bootstrap ClassLoader):
由C++写的,由JVM启动,最底层的类加载器。启动类加载器,负责加载java基础类,对应的文件是%JRE_HOME/lib/ 目录下的rt.jar、resources.jar、charsets.jar和class等。
扩展类加载器(Extension ClassLoader):
Java类,继承自URLClassLoader 。负责加载jdk自带的扩展类。对应的文件是 %JRE_HOME/lib/ext 目录下的jar和class等。
应用程序类加载器(App ClassLoader):
Java类,继承自URLClassLoader 系统类加载器,负载加载自己写的java代码。对应的文件是应用程序classpath目录下的所有jar和class等。
自定义类加载器(User ClassLoader):用户自定义加载器,不常用。
四、双亲委派机制
1)什么是双亲委派机制
除顶级类加载器外,所有其它类加载器都有其父类加载器;
如果一个类加载器收到了类加载请求,它不会首先加载这个类,而是将请求委派给父类加载器去完成,所有的加载请求最终都委派给顶层的引导类加载器,只有当父类加载器无法完成加载请求(也就是搜索范围内无该类)子加载器才会尝试自己去加载这个类;
2)那么为什么要采用双亲委派模型?
i.使得Java类随着类加载器不同而具备带优先级的层次关系,无论那个类加载器要加载该类,最终都委派给顶层引导类加载器,因此Object类在程序的各种类加载环境中都是同一个类,即可做到保证系统内防止内存中出现多份的同样的字节码。
ii.保证Java程序安全稳定运行,它实现却很简单首先检查是否被加载过,若没有加载则调用父类加载器的loadClass方法,若父类加载器为空,则默认使用引导类加载器作为父类加载器,如果加载失败,则调用自身的findClass()方法加载。
五、Class.forName()和ClassLoader.loadClass()的区别
1) Class.forName():将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的静态代码块;
2) ClassLoader.loadClass():就只将.class文件加载到jvm中,不会执行任何内容(包括静态代码块),只有在newInstance才会去执行static块。
3) Class.forName(name, initialize, loader):带参函数可控制是否加载静态代码块,并且只有调用了newInstance()方法采用调用构造函数,创建类的对象,会执行;
网友评论