//ExtClassLoader类中获取路径的代码 private static File[] getExtDirs() { //加载<JAVA_HOME>/lib/ext目录中的类库 String s = System.getProperty("java.ext.dirs"); File[] dirs; if (s != null) { StringTokenizer st = new StringTokenizer(s, File.pathSeparator); int count = st.countTokens(); dirs = new File[count]; for (int i = 0; i < count; i++) { dirs[i] = new File(st.nextToken()); } } else { dirs = new File[0]; } return dirs; }
系统(System)类加载器/应用程序类加载器
指 Sun公司实现的sun.misc.Launcher$AppClassLoader。它负责加载系统类路径java -classpath或-D java.class.path 指定路径下的类库,也就是咱们常常用到的classpath路径,开发者能够直接使用系统类加载器,通常状况下该类加载是程序中默认的类加载器,经过ClassLoader#getSystemClassLoader()方法能够获取到该类加载器。
自定义类加载器
java
//该加载器能够加载与本身在同一路径下的Class文件 public class MyClassLoader extends ClassLoader{ @Override public Class<?> loadClass(String name) throws ClassNotFoundException{ try { String fileName=name.substring(name.lastIndexOf(".")+1)+".class"; InputStream is=getClass().getResourceAsStream(fileName); if(is==null){ //不在当前路径下的类,例如Object类(JavaBean的父类),采用委派模型加载 return super.loadClass(name); }else{ //在当前路径下的类,例如JavaBean类,直接经过本身加载其Class文件 byte[] b=new byte[is.available()]; is.read(b); return defineClass(name,b,0,b.length); } } catch (IOException e) { throw new ClassNotFoundException(); } } }
对于任意一个类,都须要由加载它的类加载器和类的全限定名一同肯定其在Java虚拟机中的惟一性。
只有被同一个类加载器加载的类才可能会想等。相同的字节码被不一样的类加载器加载的类不想等。
bootstrap
public class ClassLoaderTest { public static void main(String[] args) throws Exception{ ClassLoader myLoader=new MyClassLoader(); Object classLoaderTest=myLoader.loadClass("com.loader.ClassLoaderTest").newInstance(); System.out.println(classLoaderTest.getClass()); System.out.println(classLoaderTest instanceof ClassLoaderTest); } }
class com.loader.ClassLoaderTest false
类加载器之间的层次关系,称为类加载器的双亲委派模型。双亲委派模型要求除了顶层的启动类加载器外,其他类加载器都应该有本身的父类加载器。注意,这里类加载器之间的父子关系通常不会以继承的关系实现,而是使用组合关系来复用父加载器的代码。
安全
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) { c = parent.loadClass(name, false);//委派请求给父加载器 } else { //父加载器为null,说明this为扩展类加载器的实例,父加载器为启动类加载器 c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // 若是父加载器抛出ClassNotFoundException // 说明父加载器没法完成加载请求 // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // 若是父加载器没法加载 // 调用自己的findClass方法来进行类加载 // 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; } }
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { .. if (parent != null) {//父加载器不为null,即父加载器为ClassLoader类型 c = parent.loadClass(name, false);//委派请求给父加载器 } else {//父加载器为null,说明this为扩展类加载器的实例 c = findBootstrapClassOrNull(name);//经过启动类加载器加载类 } .. }
/**经过启动类加载器加载类 * Returns a class loaded by the bootstrap class loader; * or return null if not found. */ private Class findBootstrapClassOrNull(String name) { if (!checkName(name)) return null; return findBootstrapClass(name); }
// return null if not found 启动类加载器经过本地方法加载类 private native Class findBootstrapClass(String name);默认状况下,应用程序中的类由 应用程序类加载器 ( AppClassLoader )加载。该加载器加载 系统类路径 下的类,所以通常也称为 系统类加载器 。