一.首先先说一下java虚拟机的生命周期:
1.执行了system.exit();
2.程序正常执行结束;
3.程序在执行过程中遇到了异常或错误而终止;
4.由于操作系统出现错误而导致java虚拟机进程终止;
二:ClassLoader
1.几种类加载器:
(1).Bootstrap ClassLoader:这个主要加载JVM自身工作需要的类,是由JVM自己控制的,需要加载哪个类,怎么加载都是有JVM负责的!别人访问不到这个类,所以这个ClassLoader是不遵守类加载规则的,因为它仅仅是个工具,既没有更高级的父加载器,也没有子加载器! 加载源:JRE/lib/rt.jar或者是bootclasspath选项制定的jar;
(2).ExtClassLoader: 它是JVM的一部分,它加载的目标是System.getProperty("java.ext.dirs");
(3).AppClassLoader:这个类跟我们平时打交道的比较多,在System.getProperty("java.class.path");的目录下的类都可以被这个类加载,ExtClassLoader是它的父加载器。
2.JVM记载Class的两种方式:
(1).隐式加载:通过JVM来自动加载需要的类到内存中。如:当我们引用某个类时,JVM解析这个类不再内存中,就会自动把该类加载到内存中!
(2).显式加载:通过调用ClassLoader来加载一个类的方式。下面的例程中我将会自己下个类加载器。
3.等级加载机制(父委托机制):
通过上图可以知道:当一个.class文件被JVM加载的时候,JVM首先判断是否被记载,如果被加载就结束加载过程;否则的话,就开始寻找本加载器的父类加载器,父类加载器也是先判断是否已经被加载,若没有被加载&&本加载器没有父类加载器了,就会判断应不应该由我来加载,若不应该,就会传递给它的子加载器,以此类推......
一开始我不明白,为什么JVM的类加载机制为什么要设计的这么麻烦!现在可能已经想通了:它是为了使类能够已正确的方式被应该加载它的类加载器加载!
三:.class文件如何被加载到JVM中:
(1).加载:
类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。【–从本地系统中直接加载 ,–通过网络下载.class文件 ,–从zip,jar等归档文件中加载.class文件, –从专有数据库中提取.class文件, –将Java源文件动态编译为.class文件 】
(2).验证:
类被加载后,就进入连接阶段。连接就是将已经读入到内存的类的二进制数据合并到虚拟机的运行时环境中去。【类文件的结构检查, 语义检查, 字节码验证, 二进制兼容性的验证 】
(3).准备:
为类的静态变量分配内存(方法区),并将其初始化为默认值!
(4).解析:
解析阶段是把类的二进制数据中的符号引用替换为直接应用【给Java语言带来了强大的动态扩展能力】。如:
public void sayHello(){
tdd.say();
}
在本类中,包含一个对tdd的符号引用,它是由say()方法的全名和相关描述符组成。在解析阶段,JVM会把这个符号引用替换为一个指针,改指针指向tdd类的say方法在方法区的内存位置,这个指针就是直接引用!
(5).初始化:
Java程序对类的使用方式可分为两种 :
主动使用 【创建类的实例 ,访问某个类或接口的静态变量,或者对该静态变量赋值, 调用类的静态方法, 反射(如Class.forName(“com.shengsiyuan.Test”)), 初始化一个类的子类 ,Java虚拟机启动时被标明为启动类的类(Java Test) 】
被动使用
所有的Java虚拟机实现必须在每个类或接口被Java程序“首次主动使用”时才初始化他们!
在初始化阶段,JVM执行类的初始化语句,为类的静态变量赋予初始值。在程序中,静态变量的初始化有俩种方式:(1).在静态变量的声明处进行初始化;(2)在静态代码中进行初始化。
四:常见类加载错误分析:
(1)ClassNotFoundException:
JVM要加载指定文件的字节码到内存中,并灭有找到这个文件对应的字节码,也就是这个文件不存在!检查当前的classpath下面有没有这个文件!
(2)NoClassDefFoundError:
这个有可能是你隐式加载类的时候,没有写全类名!NoClassDefFoundError的可能情况是:new 关键字,属性引用某个类,继承了某个接口或者类等等...
(3)UnsatisfiedLinkError:
如果不小心把JVM中的某个lib包删掉的话,就有可能出现这种情况。
五:实现自己的类加载器:
public class PathClassLoader extends ClassLoader {
private byte[] getData(String className) {
String path = "D:/workpace/test/build/classes/";
String namePath = className.replace(".", "/");
String classpath = path + namePath + ".class";
try {
InputStream is = new FileInputStream(new File(classpath));
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] buffer = new byte[2048];
int num = 0;
while ((num = is.read(buffer)) != -1) {
stream.write(buffer, 0, num);
}
return stream.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (name != null) {
byte[] data = getData(name);
if (data == null) {
throw new ClassNotFoundException();
} else {
return defineClass(name, data, 0, data.length);
}
} else {
return super.loadClass(name);
}
}
public static void main(String[] args) throws ClassNotFoundException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException, InstantiationException,
SecurityException, NoSuchMethodException {
PathClassLoader pathClassLoader = new PathClassLoader();
Class myClass = pathClassLoader.findClass("com.classloader.HelloWorld");
System.out.println(myClass);
Object obj = myClass.newInstance();
Method method = myClass.getMethod("say", null);
method.invoke(obj, null);
}
public class PathClassLoader extends ClassLoader {
private byte[] getData(String className) {
String path = "D:/workpace/test/build/classes/";
String namePath = className.replace(".", "/");
String classpath = path + namePath + ".class";
try {
InputStream is = new FileInputStream(new File(classpath));
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] buffer = new byte[2048];
int num = 0;
while ((num = is.read(buffer)) != -1) {
stream.write(buffer, 0, num);
}
return stream.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (name != null) {
byte[] data = getData(name);
if (data == null) {
throw new ClassNotFoundException();
} else {
return defineClass(name, data, 0, data.length);
}
} else {
return super.loadClass(name);
}
}
public static void main(String[] args) throws ClassNotFoundException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException, InstantiationException,
SecurityException, NoSuchMethodException {
PathClassLoader pathClassLoader = new PathClassLoader();
Class myClass = pathClassLoader.findClass("com.classloader.HelloWorld");
System.out.println(myClass);
Object obj = myClass.newInstance();
Method method = myClass.getMethod("say", null);
method.invoke(obj, null);
}
public class HelloWorld {
public void say(){
System.out.println("hello,world");
}
}
public class HelloWorld {
public void say(){
System.out.println("hello,world");
}
}
打印结果:
class com.classloader.HelloWorld
hello,world