美文网首页
Android_类加载_ClassLoader

Android_类加载_ClassLoader

作者: android_coder | 来源:发表于2020-01-06 00:22 被阅读0次

本文主要是基于android_10.0.0来讲述类加载的过程,涉及的代码类有

libcore/ojluni/src/main/java/java/lang/ClassLoader.java
libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
libcore/dalvik/src/main/java/dalvik/system/DexPathList.Element.java
libcore/dalvik/src/main/java/dalvik/system/DexFile.java

1:概述

我们首先从activity的实例化开始讨论,我们知道Activity的实例化在ActivityThread.java::performLaunchActivity中完成的

    Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        }
    public Activity newActivity(ClassLoader cl, String className,
            Intent intent)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        String pkg = intent != null && intent.getComponent() != null
                ? intent.getComponent().getPackageName() : null;
        return getFactory(pkg).instantiateActivity(cl, className, intent);
    }
    public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className,
            @Nullable Intent intent)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Activity) cl.loadClass(className).newInstance();
    }

我们可以看到最终是通过classLoader的loadClass根据类名去加载的

2:类的查找过程

 public Class<?> loadClass(String name) throws ClassNotFoundException {
       return loadClass(name, false);
 }
 protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
      {
              // First, check if the class has already been loaded
             Class<?> c = findLoadedClass(name);//loadedClass表示的是已经加载过得
            if (c == null) {//如果没有加载过才去加载
                 try {
                      if (parent != null) {//调用父类的classLoader去加载
                         c = parent.loadClass(name, false);
                    } else {//如果父类的classLoader为空用Boot ClassLoader去加载
                         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.
                    c = findClass(name);//用自己的
                 }
            }
            return c;
     }

3:BaseDexClassLoader.java::findClass

 protected Class<?> findClass(String name) throws ClassNotFoundException {
         throw new ClassNotFoundException(name);
     }

我们知道BaseDexClassLoader是ClassLoader的直接子类

 protected Class<?> findClass(String name) throws ClassNotFoundException {
         // First, check whether the class is present in our shared libraries.
         if (sharedLibraryLoaders != null) {//共享库对应的ClassLoader
             for (ClassLoader loader : sharedLibraryLoaders) {
                 try {
                    return loader.loadClass(name);
                } catch (ClassNotFoundException ignored) {
                }
            }
         }
         // Check whether the class in question is present in the dexPath that
         // this classloader operates on.
        List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
         Class c = pathList.findClass(name, suppressedExceptions);//调用DexPathList的findClass方法
         if (c == null) {
             ClassNotFoundException cnfe = new ClassNotFoundException(
                    "Didn't find class \"" + name + "\" on path: " + pathList);
           for (Throwable t : suppressedExceptions) {
                cnfe.addSuppressed(t);
             }
             throw cnfe;
       }
       return c;
    }

4:DexPathList.java::findClass

 public Class<?> findClass(String name, List<Throwable> suppressed) {
         for (Element element : dexElements) {//遍历Element数组去查找
            Class<?> clazz = element.findClass(name, definingContext, suppressed);
           if (clazz != null) {
               return clazz;
             }
          }
        if (dexElementsSuppressedExceptions != null) {
            suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
        }
        return null;
    }

5:DexPathList.Element.java::findClass

  public Class<?> findClass(String name, ClassLoader definingContext,
     List<Throwable> suppressed) {
     return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
      : null;
       }

6:DexFile.java::loadClassBinaryName

   private static Class defineClass(String name, ClassLoader loader, Object cookie,
                                   DexFile dexFile, List<Throwable> suppressed) {
         Class result = null;
         try {
            //通过本地方法defineClassNative来查找
            result = defineClassNative(name, loader, cookie, dexFile);
          } catch (NoClassDefFoundError e) {
          if (suppressed != null) {
                 suppressed.add(e);
            }
         } catch (ClassNotFoundException e) {
           if (suppressed != null) {
                 suppressed.add(e);
            }
         }
         return result;
     }

7:小结

7.1:双亲委派机制

类的查找是遵照双亲委派机制的,首先是判断是否已经加载过该类,如果没有则交给父类加载去加载,如果父类没有加载过就交给Boot ClassLoader(核心引导加载器)加载,如果还没有找到,则通过自身的classLoader去加载

7.2:java和android的类加载的差异

java加载的是.class,android加载的是dex,Android中没有了ExtClassLoader和AppClassLoader,取代他们的是PathClassLoader和DexClassLoader。

相关文章

网友评论

      本文标题:Android_类加载_ClassLoader

      本文链接:https://www.haomeiwen.com/subject/ghqhactx.html