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;
}
}