搜索“ClassLoader”,然后打开“java.lang”包下的ClassLoader类。然后将代码翻到loadClass方法:

    1. public Class<?> loadClass(String name) throws ClassNotFoundException {
    2. return loadClass(name, false);
    3. }
    4. protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
    5. synchronized (getClassLoadingLock(name)) {
    6. // 查找该 class 是否已经被加载过
    7. Class<?> c = findLoadedClass(name);
    8. // 如果没有加载过
    9. if (c == null) {
    10. // 委托给父加载器去加载,递归调用
    11. if (parent != null) {
    12. c = parent.loadClass(name, false);
    13. } else {
    14. // 如果父加载器为空,查找 Bootstrap 是否加载过
    15. c = findBootstrapClassOrNull(name);
    16. }
    17. // 若果依然加载不到,则调用自己的 findClass 去加载
    18. if (c == null) {
    19. c = findClass(name);
    20. }
    21. }
    22. if (resolve) {
    23. resolveClass(c);
    24. }
    25. return c;
    26. }
    27. }
    28. protected Class<?> findClass(String name){
    29. //1. 根据传入的类名 name,到在特定目录下去寻找类文件,把.class 文件读入内存
    30. ...
    31. //2. 调用 defineClass 将字节数组转成 Class 对象
    32. return defineClass(buf, off, len);
    33. }
    34. // 将字节码数组解析成一个 Class 对象,用 native 方法实现
    35. protected final Class<?> defineClass(byte[] b, int off, int len){
    36. ...
    37. }

    这段代码已经很好的解释了双亲委派机制,一张图来描述一下上面这段代码的流程:
    20201217213314510.png
    当类加载器收到一个类的加载请求时,首先会检查是否加载过,如果有就无须再加载了,如果没有将这个请求委派给父类加载器去加载,调用父加载器的loadClass方法。如果没有再往上,直到到达Bootstrap classLoader之前,都是在检查是否加载过,并不会选择自己去加载。如果没有父类加载器,这时候会考虑自己是否能加载了,如果无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出ClassNotFoundException。