一 Java Class文件
java的class文件是java文件通过javac编译之后得到的jvm可执行的文件,以.class结尾的文件。
二 Java Class 对象的生命周期
java对象的生命周期如下图所示:
三 类加载器
上述Java Class对象的生命周期中的第一步,load class的流程里面就是实质上就是java的类加载器加载磁盘上的*.class文件,加载到内存中。类加载器到底是如何工作的呢?下面将来讲解下类加载器。
java中的类加载器分为四大类:BootStrapClassLoader, ExtensionClassLoader, AppClassLoader, 自定义类加载器。
BootStrap ClassLoader: 根类加载器, 主要加载的是rt.jar, charset.jar等相关的jar里面的class
ExtensionClassLoader: 扩展类加载器, 主要加载java.ext.dirs这个参数所对应的文件里面的.class,例如:D:\Java1.8\jdk1.8.0_191\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
AppClassLoader:系统类加载器,主要加载应用程序的代码,classpatch目录下的类。、
自定义类加载器 : 自己设置加载文件的目录。自定义类加载器要继承ClassLoader类,重写findClass方法,findClass中要调用defineClass方法,从而返回一个Class<?>的对象。
获取类加载器的代码如下所示:
package zd.classLoader;
import java.net.URL;
import zd.hash.HashTest;
public class ClassLoaderTest {
public static void main(String[] args){
//HashTest是我们代码里面写的类, HashTest.class.getClassLoader()//获取到加载我们自己写的类的类加载器
ClassLoader appLoad= HashTest.class.getClassLoader();
//输出类加载器为sun.misc.Launcher$AppClassLoader@73d16e93,由此可见,我们写的业务代码的类加载器是AppClassLoader这个类加载器加载到内存中去的
System.out.println(appLoad);
//获取类加载器sun.misc.Launcher$AppClassLoader的父类加载器sun.misc.Launcher$ExtClassLoader(需要特殊说明的是AppClassLoader和ExtClassLoader并不存在继承关系)
ClassLoader extLoad= HashTest.class.getClassLoader().getParent();
System.out.println(extLoad);
//获取到ExtClassLoader类加载器要加载的目录,输出为D:\Java1.8\jdk1.8.0_191\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
//表明ExtClassLoader类加载器获取加载上述目录中的所有的jar里面的.class文件
String extDirs = System.getProperty("java.ext.dirs");
System.out.println(extDirs);
//获取到根类加载器要加载的资源内容
//输出结果如下
//file:/D:/Java1.8/jdk1.8.0_191/jre/lib/resources.jar
//file:/D:/Java1.8/jdk1.8.0_191/jre/lib/rt.jar
//file:/D:/Java1.8/jdk1.8.0_191/jre/lib/sunrsasign.jar
//file:/D:/Java1.8/jdk1.8.0_191/jre/lib/jsse.jar
//file:/D:/Java1.8/jdk1.8.0_191/jre/lib/jce.jar
//file:/D:/Java1.8/jdk1.8.0_191/jre/lib/charsets.jar
//file:/D:/Java1.8/jdk1.8.0_191/jre/lib/jfr.jar
//file:/D:/Java1.8/jdk1.8.0_191/jre/classes
URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
for(URL url : urls){
System.out.println(url.toString());
}
}
}
自定义类加载器代码如下: 自定义类加载器的代码比较简单,这里我就不过多说明了
package zd.classLoader;
import java.lang.reflect.Method;
public class MyClassLoadMain {
public static void main(String[] args){
MyClassLoderTest test = new MyClassLoderTest();
try {
Class<?> cls = test.findClass("zd.classLoader.Test");
Method[] methords = cls.getDeclaredMethods();
Object o = cls.newInstance();
for(Method m : methords){
if(m.getParameterCount() == 0){
System.out.println(m.invoke(o, null));
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package zd.classLoader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class MyClassLoderTest extends ClassLoader {
@Override
public Class<?> findClass(String name) throws ClassNotFoundException{
String namePath = name.replaceAll("\\.", "\\\\");
File file = new File("D:\\"+File.separator+namePath+".class");
ByteArrayOutputStream os = null;
InputStream is = null;
try {
is = new FileInputStream(file);
os = new ByteArrayOutputStream();
int length = 0;
byte[] bytes = new byte[1024];
while((length = is.read(bytes)) != -1){
os.write(bytes, 0, length);
}
byte[] classBytes = os.toByteArray();
return defineClass(name, classBytes, 0, classBytes.length);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try{
if(os != null){
os.close();
}
if(is != null){
is.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
return super.findClass(name);
}
}
package zd.classLoader;
public class Test {
private static String a = "123";
public static String getA() {
return a;
}
public static void setA(String a) {
Test.a = a;
}
}
类加载器是属于双亲委派的方式去加载对应的class文件的。首先AppClassLoader去加载class文件的时候,先去缓存中找(已经加载进去了的class), 如果没有,则去让父加载器找,也就是ExtClassLoader类加载器,父类加载器也从自己的缓存中去查找,如果没有, 再去让父类加载器加载, 也就是BootStrapClassLoader,BootStrapClassLoader的缓存中没有,则到其应该加载的class的目录中去找,如果没有,再委派给子类加载器ExtClassLoader。ExtClassLoader也去其应该加载的class的目录中去找,如果没有,再委托给其子类加载器AppClassLoader. 如果AppClassLoader 没有找到,则抛出ClassNotFoundException。ClassLoader的类加载示意图如下所示: