Java的类加载器都有哪些?
每个类加载器都加载哪些类?
这些类加载之间的父子关系是怎样的?
什么是双亲委派模型?
为什么Java的类加载器要使用双亲委派模型?
如何自定义自己的类加载器,自己的类加载器和Java自带的类加载器关系如何处理?
默认的类加载器只知道如何从本地系统加载类。如果我们的程序只是在本机跑的话,一般来说默认加载器可以应付。 但是如果我们需要加载远程服务器的类,或者说加载网络上的,不是本机上的类的时候,就需要到自定义类加载器。
实现方式:
自定义类加载器可以选择 继承ClassLoader类,重写里面的方法来实现。
1、loadClass(String name,Boolean resolve)方法:不推荐重写,因为loadClass()方法做的工作主要为实现双亲委托模型,我们重写的话可能会破坏该模型,并且也增加自己的开发难度。
2、defineClass(String name,byte[] b,int off,int len)方法,主要用于将原始字节转换为Class对象,也不需要我们重写。
3、findClass(String name)方法,根据名称来查找类。把.class文件的内容放入一个byte[]数组中,供defineClass()方法使用。一般我们就重写这个方法。在这个方法中,我们重新定义从哪里,怎么样读取文件内容。这样我们就可以把从本机上改为从网络上得到类,从而实现自定义类加载器。
步骤:
1、继承ClassLoader类。
2、重写findClass(String name)方法。 在这个方法里面我们重新定义从哪里,怎么读取文件内容到byte[]数组中,供defineClass()使用
package com.study.pattern;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
/**
* Created by WuTing on 2018/3/6.
*/
public class MyClassLoader extends ClassLoader {
private static final String FILE_TYPE = ".class";
private String path;
public MyClassLoader() {
super();
}
public MyClassLoader(ClassLoader parent) {
super(parent);
}
@Override
public Class<?> loadClass(String classFullName) throws ClassNotFoundException {
return super.loadClass(classFullName);
}
@Override
protected Class<?> loadClass(String classFullName, boolean resolve) throws ClassNotFoundException {
return super.loadClass(classFullName, resolve);
}
@Override
protected Class<?> findClass(String classFullName) throws ClassNotFoundException {
byte[] data = this.loadClassData(classFullName);
return this.defineClass(classFullName, data, 0, data.length);
}
private byte[] loadClassData(String classFullName) {
InputStream is = null;
byte[] data = null;
ByteArrayOutputStream outputStream = null;
try {
String pathname = getPath() + classFullName.replace(".", "\\") + FILE_TYPE;
is = new FileInputStream(new File(pathname));
outputStream = new ByteArrayOutputStream();
int ch = 0;
while (-1 != (ch = is.read())) {
outputStream.write(ch);
}
data = outputStream.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
is.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return data;
}
public static void showClassLoader(ClassLoader loader) throws Exception {
Class clazz = loader.loadClass("com.study.pattern.Sample"); //Class 全名
clazz.newInstance();
}
public static void main(String[] args) throws Exception {
MyClassLoader loader1 = new MyClassLoader();
loader1.setPath("d:\\loader1\\");
MyClassLoader loader2 = new MyClassLoader(loader1);
loader2.setPath("d:\\loader2\\");
MyClassLoader loader3 = new MyClassLoader(null);
loader3.setPath("d:\\loader3\\");
showClassLoader(loader1);
showClassLoader(loader2);
showClassLoader(loader3);
}
public String getPath() {
if (path == null || path.trim().length() == 0) {
path = Thread.currentThread().getContextClassLoader().getResource("").getPath();
}
return path;
}
public void setPath(String path) {
this.path = path;
}
}
package com.study.pattern;
/**
* Created by WuTing on 2018/3/6.
*/
public class Sample {
public Sample() {
System.out.println("Sample is load by :" + this.getClass().getClassLoader());
}
}
执行结果:
Sample is load by :sun.misc.Launcher$AppClassLoader@18b4aac2
Sample is load by :sun.misc.Launcher$AppClassLoader@18b4aac2
Sample is load by :com.study.pattern.MyClassLoader@1540e19d
从结果可以看出,当指定了指定了parent,会调用parent的findClass.
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) { //存在parent,调用parent的loadClass
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}