- 浏览: 23784 次
- 性别:
- 来自: 北京
-
最近访客 更多访客>>
文章分类
最新评论
-
xiaofeishouxiao:
能给一个源码吗
Android JNI Demo -
rayleeya:
好,楼主讲的太好了~第一次见到这么好的帖子
Android Query & managedQuery
ClassLoader
bootstrap classloader(启动类加载器)
>>这个ClassLoader在JVM运行的时候加载java核心的API以满足java程序最基本的需求,其中就包括用户定义的ClassLoader
通过java程序实现的ClassLoader:
>>ExtClassLoader : 这个ClassLoader是用来加载java的扩展API的,也就是/lib/ext中的类.
>>AppClassLoader : 这个 ClassLoader是用来加载用户机器上CLASSPATH设置目录中的Class的,通常在没有指定ClassLoader的情况下,程序员自定义的类就由该ClassLoader进行加载.
程序运行:
当运行一个程序的时候,JVM启动,运行bootstrap classloader,该ClassLoader加载java核心API(ExtClassLoader和AppClassLoader也在此时被加载),然后调用ExtClassLoader加载扩展API,最后AppClassLoader加载CLASSPATH目录下定义的Class,这就是一个程序最基本的加载流程。
上面大概讲解了一下ClassLoader的作用以及一个最基本的加载流程,接下来将讲解一下ClassLoader加载的方式,这里就不得不讲一下ClassLoader在这里使用了双亲委托模式进行类加载。
每一个自定义ClassLoader都必须继承ClassLoader这个抽象类,而每个ClassLoader都会有一个parent ClassLoader,我们可以看一下ClassLoader这个抽象类中有一个getParent()方法,这个方法用来返回当前 ClassLoader的parent,注意,这个parent不是指的被继承的类,而是在实例化该ClassLoader时指定的一个 ClassLoader,如果这个parent为null,那么就默认该ClassLoader的parent是bootstrap classloader,这个parent有什么用呢?
我们可以考虑这样一种情况,假设我们自定义了一个 ClientDefClassLoader,我们使用这个自定义的ClassLoader加载java.lang.String,那么这里String是否会被这个ClassLoader加载呢?事实上java.lang.String这个类并不是被这个ClientDefClassLoader加载,而是由bootstrap classloader进行加载,为什么会这样?实际上这就是双亲委托模式的原因,因为在任何一个自定义ClassLoader加载一个类之前,它都会先委托它的父亲ClassLoader进行加载,只有当父亲ClassLoader无法加载成功后,才会由自己加载,在上面这个例子里,因为 java.lang.String是属于java核心API的一个类,所以当使用ClientDefClassLoader加载它的时候,该 ClassLoader会先委托它的父亲ClassLoader进行加载,上面讲过,当ClassLoader的parent为null 时,ClassLoader的parent就是bootstrap classloader,所以在ClassLoader的最顶层就是bootstrap classloader,因此最终委托到bootstrap classloader的时候,bootstrap classloader就会返回String的Class。
为什么要使用这种双亲委托模式呢?
第一个原因就是因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。
第二个原因就是考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String已经在启动时被加载,所以用户自定义类是无法加载一个自定义的 ClassLoader。
ClassLoader.java
DexClassLoader.java
PathClassLoader.java
bootstrap classloader(启动类加载器)
>>这个ClassLoader在JVM运行的时候加载java核心的API以满足java程序最基本的需求,其中就包括用户定义的ClassLoader
通过java程序实现的ClassLoader:
>>ExtClassLoader : 这个ClassLoader是用来加载java的扩展API的,也就是/lib/ext中的类.
>>AppClassLoader : 这个 ClassLoader是用来加载用户机器上CLASSPATH设置目录中的Class的,通常在没有指定ClassLoader的情况下,程序员自定义的类就由该ClassLoader进行加载.
程序运行:
当运行一个程序的时候,JVM启动,运行bootstrap classloader,该ClassLoader加载java核心API(ExtClassLoader和AppClassLoader也在此时被加载),然后调用ExtClassLoader加载扩展API,最后AppClassLoader加载CLASSPATH目录下定义的Class,这就是一个程序最基本的加载流程。
上面大概讲解了一下ClassLoader的作用以及一个最基本的加载流程,接下来将讲解一下ClassLoader加载的方式,这里就不得不讲一下ClassLoader在这里使用了双亲委托模式进行类加载。
每一个自定义ClassLoader都必须继承ClassLoader这个抽象类,而每个ClassLoader都会有一个parent ClassLoader,我们可以看一下ClassLoader这个抽象类中有一个getParent()方法,这个方法用来返回当前 ClassLoader的parent,注意,这个parent不是指的被继承的类,而是在实例化该ClassLoader时指定的一个 ClassLoader,如果这个parent为null,那么就默认该ClassLoader的parent是bootstrap classloader,这个parent有什么用呢?
我们可以考虑这样一种情况,假设我们自定义了一个 ClientDefClassLoader,我们使用这个自定义的ClassLoader加载java.lang.String,那么这里String是否会被这个ClassLoader加载呢?事实上java.lang.String这个类并不是被这个ClientDefClassLoader加载,而是由bootstrap classloader进行加载,为什么会这样?实际上这就是双亲委托模式的原因,因为在任何一个自定义ClassLoader加载一个类之前,它都会先委托它的父亲ClassLoader进行加载,只有当父亲ClassLoader无法加载成功后,才会由自己加载,在上面这个例子里,因为 java.lang.String是属于java核心API的一个类,所以当使用ClientDefClassLoader加载它的时候,该 ClassLoader会先委托它的父亲ClassLoader进行加载,上面讲过,当ClassLoader的parent为null 时,ClassLoader的parent就是bootstrap classloader,所以在ClassLoader的最顶层就是bootstrap classloader,因此最终委托到bootstrap classloader的时候,bootstrap classloader就会返回String的Class。
为什么要使用这种双亲委托模式呢?
第一个原因就是因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。
第二个原因就是考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String已经在启动时被加载,所以用户自定义类是无法加载一个自定义的 ClassLoader。
ClassLoader.java
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package java.lang; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.nio.ByteBuffer; import java.security.ProtectionDomain; import java.util.Collection; import java.util.Enumeration; import java.util.Map; import java.util.HashMap; import dalvik.system.PathClassLoader; import dalvik.system.VMStack; /** * Loads classes and resources from a repository. One or more class loaders are * installed at runtime. These are consulted whenever the runtime system needs a * specific class that is not yet available in-memory. Typically, class loaders * are grouped into a tree where child class loaders delegate all requests to * parent class loaders. Only if the parent class loader cannot satisfy the * request, the child class loader itself tries to handle it. * <p> * {@code ClassLoader} is an abstract class that implements the common * infrastructure required by all class loaders. Android provides several * concrete implementations of the class, with * {@link dalvik.system.PathClassLoader} being the one typically used. Other * applications may implement subclasses of {@code ClassLoader} to provide * special ways for loading classes. * </p> * * @since Android 1.0 * @see Class */ public abstract class ClassLoader { // BEGIN android-note /* * Because of a potential class initialization race between ClassLoader and * java.lang.System, reproducible when using JDWP with "suspend=y", we defer * creation of the system class loader until first use. We use a static * inner class to get synchronization at init time without having to sync on * every access. */ // END android-note /** * The 'System' ClassLoader - the one that is responsible for loading * classes from the classpath. It is not equal to the bootstrap class loader - * that one handles the built-in classes. * * @see #getSystemClassLoader() */ static private class SystemClassLoader { public static ClassLoader loader = ClassLoader.createSystemClassLoader(); } /** * The parent ClassLoader. */ private ClassLoader parent; /** * The packages known to the class loader. */ private Map<String, Package> packages = new HashMap<String, Package>(); /** * Create the system class loader. Note this is NOT the bootstrap class * loader (which is managed by the VM). We use a null value for the parent * to indicate that the bootstrap loader is our parent. */ private static ClassLoader createSystemClassLoader() { String classPath = System.getProperty("java.class.path", "."); // String[] paths = classPath.split(":"); // URL[] urls = new URL[paths.length]; // for (int i = 0; i < paths.length; i++) { // try { // urls[i] = new URL("file://" + paths[i]); // } // catch (Exception ex) { // ex.printStackTrace(); // } // } // // return new java.net.URLClassLoader(urls, null); // TODO Make this a java.net.URLClassLoader once we have those? return new PathClassLoader(classPath, BootClassLoader.getInstance()); } /** * Returns the system class loader. This is the parent for new * {@code ClassLoader} instances and is typically the class loader used to * start the application. If a security manager is present and the caller's * class loader is neither {@code null} nor the same as or an ancestor of * the system class loader, then this method calls the security manager's * checkPermission method with a RuntimePermission("getClassLoader") * permission to ensure that it is ok to access the system class loader. If * not, a {@code SecurityException} is thrown. * * @return the system class loader. * @throws SecurityException * if a security manager exists and it does not allow access to * the system class loader. * @since Android 1.0 */ public static ClassLoader getSystemClassLoader() { SecurityManager smgr = System.getSecurityManager(); if (smgr != null) { ClassLoader caller = VMStack.getCallingClassLoader(); if (caller != null && !caller.isAncestorOf(SystemClassLoader.loader)) { smgr.checkPermission(new RuntimePermission("getClassLoader")); } } return SystemClassLoader.loader; } /** * Finds the URL of the resource with the specified name. The system class * loader's resource lookup algorithm is used to find the resource. * * @return the {@code URL} object for the requested resource or {@code null} * if the resource can not be found. * @param resName * the name of the resource to find. * @see Class#getResource * @since Android 1.0 */ public static URL getSystemResource(String resName) { return SystemClassLoader.loader.getResource(resName); } /** * Returns an enumeration of URLs for the resource with the specified name. * The system class loader's resource lookup algorithm is used to find the * resource. * * @return an enumeration of {@code URL} objects containing the requested * resources. * @param resName * the name of the resource to find. * @throws IOException * if an I/O error occurs. * @since Android 1.0 */ public static Enumeration<URL> getSystemResources(String resName) throws IOException { return SystemClassLoader.loader.getResources(resName); } /** * Returns a stream for the resource with the specified name. The system * class loader's resource lookup algorithm is used to find the resource. * Basically, the contents of the java.class.path are searched in order, * looking for a path which matches the specified resource. * * @return a stream for the resource or {@code null}. * @param resName * the name of the resource to find. * @see Class#getResourceAsStream * @since Android 1.0 */ public static InputStream getSystemResourceAsStream(String resName) { return SystemClassLoader.loader.getResourceAsStream(resName); } /** * Constructs a new instance of this class with the system class loader as * its parent. * * @throws SecurityException * if a security manager exists and it does not allow the * creation of a new {@code ClassLoader}. * @since Android 1.0 */ protected ClassLoader() { this(getSystemClassLoader(), false); } /** * Constructs a new instance of this class with the specified class loader * as its parent. * * @param parentLoader * The {@code ClassLoader} to use as the new class loader's * parent. * @throws SecurityException * if a security manager exists and it does not allow the * creation of new a new {@code ClassLoader}. * @since Android 1.0 */ protected ClassLoader(ClassLoader parentLoader) { this(parentLoader, false); } /* * constructor for the BootClassLoader which needs parent to be null. */ ClassLoader(ClassLoader parentLoader, boolean nullAllowed) { SecurityManager smgr = System.getSecurityManager(); if (smgr != null) { smgr.checkCreateClassLoader(); } if (parentLoader == null && !nullAllowed) { throw new NullPointerException( "Parent ClassLoader may not be null"); } parent = parentLoader; } /** * Constructs a new class from an array of bytes containing a class * definition in class file format. * * @param classRep * the memory image of a class file. * @param offset * the offset into {@code classRep}. * @param length * the length of the class file. * @return the {@code Class} object created from the specified subset of * data in {@code classRep}. * @throws ClassFormatError * if {@code classRep} does not contain a valid class. * @throws IndexOutOfBoundsException * if {@code offset < 0}, {@code length < 0} or if * {@code offset + length} is greater than the length of * {@code classRep}. * @deprecated Use {@link #defineClass(String, byte[], int, int)} * @since Android 1.0 */ @Deprecated protected final Class<?> defineClass(byte[] classRep, int offset, int length) throws ClassFormatError { return VMClassLoader.defineClass(this, classRep, offset, length, null); } /** * Constructs a new class from an array of bytes containing a class * definition in class file format. * * @param className * the expected name of the new class, may be {@code null} if not * known. * @param classRep * the memory image of a class file. * @param offset * the offset into {@code classRep}. * @param length * the length of the class file. * @return the {@code Class} object created from the specified subset of * data in {@code classRep}. * @throws ClassFormatError * if {@code classRep} does not contain a valid class. * @throws IndexOutOfBoundsException * if {@code offset < 0}, {@code length < 0} or if * {@code offset + length} is greater than the length of * {@code classRep}. * @since Android 1.0 */ protected final Class<?> defineClass(String className, byte[] classRep, int offset, int length) throws ClassFormatError { // TODO Define a default ProtectionDomain on first use return defineClass(className, classRep, offset, length, null); } /** * Constructs a new class from an array of bytes containing a class * definition in class file format and assigns the specified protection * domain to the new class. If the provided protection domain is * {@code null} then a default protection domain is assigned to the class. * * @param className * the expected name of the new class, may be {@code null} if not * known. * @param classRep * the memory image of a class file. * @param offset * the offset into {@code classRep}. * @param length * the length of the class file. * @param protectionDomain * the protection domain to assign to the loaded class, may be * {@code null}. * @return the {@code Class} object created from the specified subset of * data in {@code classRep}. * @throws ClassFormatError * if {@code classRep} does not contain a valid class. * @throws IndexOutOfBoundsException * if {@code offset < 0}, {@code length < 0} or if * {@code offset + length} is greater than the length of * {@code classRep}. * @throws NoClassDefFoundError * if {@code className} is not equal to the name of the class * contained in {@code classRep}. * @since Android 1.0 */ protected final Class<?> defineClass(String className, byte[] classRep, int offset, int length, ProtectionDomain protectionDomain) throws java.lang.ClassFormatError { return VMClassLoader.defineClass(this, className, classRep, offset, length, protectionDomain); } /** * Defines a new class with the specified name, byte code from the byte * buffer and the optional protection domain. If the provided protection * domain is {@code null} then a default protection domain is assigned to * the class. * * @param name * the expected name of the new class, may be {@code null} if not * known. * @param b * the byte buffer containing the byte code of the new class. * @param protectionDomain * the protection domain to assign to the loaded class, may be * {@code null}. * @return the {@code Class} object created from the data in {@code b}. * @throws ClassFormatError * if {@code b} does not contain a valid class. * @throws NoClassDefFoundError * if {@code className} is not equal to the name of the class * contained in {@code b}. * @since Android 1.0 */ protected final Class<?> defineClass(String name, ByteBuffer b, ProtectionDomain protectionDomain) throws ClassFormatError { byte[] temp = new byte[b.remaining()]; b.get(temp); return defineClass(name, temp, 0, temp.length, protectionDomain); } /** * Overridden by subclasses, throws a {@code ClassNotFoundException} by * default. This method is called by {@code loadClass} after the parent * {@code ClassLoader} has failed to find a loaded class of the same name. * * @param className * the name of the class to look for. * @return the {@code Class} object that is found. * @throws ClassNotFoundException * if the class cannot be found. * @since Android 1.0 */ protected Class<?> findClass(String className) throws ClassNotFoundException { throw new ClassNotFoundException(className); } /** * Returns the class with the specified name if it has already been loaded * by the virtual machine or {@code null} if it has not yet been loaded. * * @param className * the name of the class to look for. * @return the {@code Class} object or {@code null} if the requested class * has not been loaded. * @since Android 1.0 */ protected final Class<?> findLoadedClass(String className) { ClassLoader loader; if (this == BootClassLoader.getInstance()) loader = null; else loader = this; return VMClassLoader.findLoadedClass(loader, className); } /** * Finds the class with the specified name, loading it using the system * class loader if necessary. * * @param className * the name of the class to look for. * @return the {@code Class} object with the requested {@code className}. * @throws ClassNotFoundException * if the class can not be found. * @since Android 1.0 */ protected final Class<?> findSystemClass(String className) throws ClassNotFoundException { return Class.forName(className, false, getSystemClassLoader()); } /** * Returns this class loader's parent. * * @return this class loader's parent or {@code null}. * @throws SecurityException * if a security manager exists and it does not allow to * retrieve the parent class loader. * @since Android 1.0 */ public final ClassLoader getParent() { SecurityManager smgr = System.getSecurityManager(); if (smgr != null) { smgr.checkPermission(new RuntimePermission("getClassLoader")); } return parent; } /** * Returns the URL of the resource with the specified name. This * implementation first tries to use the parent class loader to find the * resource; if this fails then {@link #findResource(String)} is called to * find the requested resource. * * @param resName * the name of the resource to find. * @return the {@code URL} object for the requested resource or {@code null} * if either the resource can not be found or a security manager * does not allow to access the resource. * @see Class#getResource * @since Android 1.0 */ public URL getResource(String resName) { URL resource = null; resource = parent.getResource(resName); if (resource == null) { resource = findResource(resName); } return resource; } /** * Returns an enumeration of URLs for the resource with the specified name. * This implementation first uses this class loader's parent to find the * resource, then it calls {@link #findResources(String)} to get additional * URLs. The returned enumeration contains the {@code URL} objects of both * find operations. * * @return an enumeration of {@code URL} objects for the requested resource. * @param resName * the name of the resource to find. * @throws IOException * if an I/O error occurs. * @since Android 1.0 */ @SuppressWarnings("unchecked") public Enumeration<URL> getResources(String resName) throws IOException { Enumeration first = parent.getResources(resName); Enumeration second = findResources(resName); return new TwoEnumerationsInOne(first, second); } /** * Returns a stream for the resource with the specified name. See * {@link #getResource(String)} for a description of the lookup algorithm * used to find the resource. * * @return a stream for the resource or {@code null} if either the resource * can not be found or a security manager does not allow to access * the resource. * @param resName * the name of the resource to find. * @see Class#getResourceAsStream * @since Android 1.0 */ public InputStream getResourceAsStream(String resName) { try { URL url = getResource(resName); if (url != null) { return url.openStream(); } } catch (IOException ex) { // Don't want to see the exception. } return null; } /** * Loads the class with the specified name. Invoking this method is * equivalent to calling {@code loadClass(className, false)}. * <p> * <strong>Note:</strong> In the Android reference implementation, the * second parameter of {@link #loadClass(String, boolean)} is ignored * anyway. * </p> * * @return the {@code Class} object. * @param className * the name of the class to look for. * @throws ClassNotFoundException * if the class can not be found. * @since Android 1.0 */ public Class<?> loadClass(String className) throws ClassNotFoundException { return loadClass(className, false); } /** * Loads the class with the specified name, optionally linking it after * loading. The following steps are performed: * <ol> * <li> Call {@link #findLoadedClass(String)} to determine if the requested * class has already been loaded.</li> * <li>If the class has not yet been loaded: Invoke this method on the * parent class loader.</li> * <li>If the class has still not been loaded: Call * {@link #findClass(String)} to find the class.</li> * </ol> * <p> * <strong>Note:</strong> In the Android reference implementation, the * {@code resolve} parameter is ignored; classes are never linked. * </p> * * @return the {@code Class} object. * @param className * the name of the class to look for. * @param resolve * Indicates if the class should be resolved after loading. This * parameter is ignored on the Android reference implementation; * classes are not resolved. * @throws ClassNotFoundException * if the class can not be found. * @since Android 1.0 */ protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException { Class<?> clazz = findLoadedClass(className); if (clazz == null) { try { clazz = parent.loadClass(className, false); } catch (ClassNotFoundException e) { // Don't want to see this. } if (clazz == null) { clazz = findClass(className); } } return clazz; } /** * Forces a class to be linked (initialized). If the class has already been * linked this operation has no effect. * <p> * <strong>Note:</strong> In the Android reference implementation, this * method has no effect. * </p> * * @param clazz * the class to link. * @since Android 1.0 */ protected final void resolveClass(Class<?> clazz) { // no-op, doesn't make sense on android. } /** * Indicates whether this class loader is the system class loader. This * method must be provided by the virtual machine vendor, as it is used by * other provided class implementations in this package. A sample * implementation of this method is provided by the reference * implementation. This method is used by * SecurityManager.classLoaderDepth(), currentClassLoader() and * currentLoadedClass(). Returns true if the receiver is a system class * loader. * <p> * Note that this method has package visibility only. It is defined here to * avoid the security manager check in getSystemClassLoader, which would be * required to implement this method anywhere else. * </p> * * @return {@code true} if the receiver is a system class loader * @see Class#getClassLoaderImpl() */ final boolean isSystemClassLoader() { return false; } /** * <p> * Returns true if the receiver is ancestor of another class loader. It also * returns true if the two class loader are equal. * </p> * <p> * Note that this method has package visibility only. It is defined here to * avoid the security manager check in getParent, which would be required to * implement this method anywhere else. The method is also required in other * places where class loaders are accesses. * </p> * * @param child * A child candidate * @return {@code true} if the receiver is ancestor of, or equal to, * the parameter */ final boolean isAncestorOf(ClassLoader child) { for (ClassLoader current = child; current != null; current = current.parent) { if (current == this) { return true; } } return false; } /** * Finds the URL of the resource with the specified name. This * implementation just returns {@code null}; it should be overridden in * subclasses. * * @param resName * the name of the resource to find. * @return the {@code URL} object for the requested resource. * @since Android 1.0 */ protected URL findResource(String resName) { return null; } /** * Finds an enumeration of URLs for the resource with the specified name. * This implementation just returns an empty {@code Enumeration}; it should * be overridden in subclasses. * * @param resName * the name of the resource to find. * @return an enumeration of {@code URL} objects for the requested resource. * @throws IOException * if an I/O error occurs. * @since Android 1.0 */ @SuppressWarnings( { "unchecked", "unused" }) protected Enumeration<URL> findResources(String resName) throws IOException { return EmptyEnumeration.getInstance(); } /** * Returns the absolute path of the native library with the specified name, * or {@code null}. If this method returns {@code null} then the virtual * machine searches the directories specified by the system property * "java.library.path". * <p> * This implementation always returns {@code null}. * </p> * * @param libName * the name of the library to find. * @return the absolute path of the library. * @since Android 1.0 */ protected String findLibrary(String libName) { return null; } /** * Returns the package with the specified name. Package information is * searched in this class loader. * * @param name * the name of the package to find. * @return the package with the requested name; {@code null} if the package * can not be found. * @since Android 1.0 */ protected Package getPackage(String name) { synchronized (packages) { Package p = packages.get(name); return p; } } /** * Gets the package with the specified name, searching it in the specified * class loader. * * @param loader * the class loader to search the package in. * @param name * the name of the package to find. * @return the package with the requested name; {@code null} if the package * can not be found. * @since Android 1.0 */ static Package getPackage(ClassLoader loader, String name) { return loader.getPackage(name); } /** * Returns all the packages known to this class loader. * * @return an array with all packages known to this class loader. * @since Android 1.0 */ protected Package[] getPackages() { synchronized (packages) { Collection<Package> col = packages.values(); Package[] result = new Package[col.size()]; col.toArray(result); return result; } } /** * Defines and returns a new {@code Package} using the specified * information. If {@code sealBase} is {@code null}, the package is left * unsealed. Otherwise, the package is sealed using this URL. * * @param name * the name of the package. * @param specTitle * the title of the specification. * @param specVersion * the version of the specification. * @param specVendor * the vendor of the specification. * @param implTitle * the implementation title. * @param implVersion * the implementation version. * @param implVendor * the specification vendor. * @param sealBase * the URL used to seal this package or {@code null} to leave the * package unsealed. * @return the {@code Package} object that has been created. * @throws IllegalArgumentException * if a package with the specified name already exists. * @since Android 1.0 */ protected Package definePackage(String name, String specTitle, String specVersion, String specVendor, String implTitle, String implVersion, String implVendor, URL sealBase) throws IllegalArgumentException { synchronized (packages) { if (packages.containsKey(name)) { throw new IllegalArgumentException("Package " + name + " already defined"); } Package newPackage = new Package(name, specTitle, specVersion, specVendor, implTitle, implVersion, implVendor, sealBase); packages.put(name, newPackage); return newPackage; } } /** * Gets the signers of the specified class. This implementation returns * {@code null}. * * @param c * the {@code Class} object for which to get the signers. * @return signers the signers of {@code c}. * @since Android 1.0 */ final Object[] getSigners(Class<?> c) { return null; } /** * Sets the signers of the specified class. This implementation does * nothing. * * @param c * the {@code Class} object for which to set the signers. * @param signers * the signers for {@code c}. * @since Android 1.0 */ protected final void setSigners(Class<?> c, Object[] signers) { return; } /** * <p> * This must be provided by the VM vendor. It is used by * SecurityManager.checkMemberAccess() with depth = 3. Note that * checkMemberAccess() assumes the following stack when called:<br> * </p> * * <pre> * < user code &gt; <- want this class * Class.getDeclared*(); * Class.checkMemberAccess(); * SecurityManager.checkMemberAccess(); <- current frame * </pre> * * <p> * Returns the ClassLoader of the method (including natives) at the * specified depth on the stack of the calling thread. Frames representing * the VM implementation of java.lang.reflect are not included in the list. * </p> * Notes: * <ul> * <li>This method operates on the defining classes of methods on stack. * NOT the classes of receivers.</li> * <li>The item at depth zero is the caller of this method</li> * </ul> * * @param depth * the stack depth of the requested ClassLoader * @return the ClassLoader at the specified depth */ static final ClassLoader getStackClassLoader(int depth) { Class<?>[] stack = VMStack.getClasses(depth + 1, false); if(stack.length < depth + 1) { return null; } return stack[depth].getClassLoader(); } /** * This method must be provided by the VM vendor, as it is called by * java.lang.System.loadLibrary(). System.loadLibrary() cannot call * Runtime.loadLibrary() because this method loads the library using the * ClassLoader of the calling method. Loads and links the library specified * by the argument. * * @param libName * the name of the library to load * @param loader * the classloader in which to load the library * @throws UnsatisfiedLinkError * if the library could not be loaded * @throws SecurityException * if the library was not allowed to be loaded * <p> * <strong>Note: </strong>This method does nothing in the Android reference * implementation. * </p> */ static void loadLibraryWithClassLoader(String libName, ClassLoader loader) { return; } /** * This method must be provided by the VM vendor, as it is called by * java.lang.System.load(). System.load() cannot call Runtime.load() because * the library is loaded using the ClassLoader of the calling method. Loads * and links the library specified by the argument. No security check is * done. * <p> * <strong>Note: </strong>This method does nothing in the Android reference * implementation. * </p> * * @param libName * the name of the library to load * @param loader * the classloader in which to load the library * @param libraryPath * the library path to search, or null * @throws UnsatisfiedLinkError * if the library could not be loaded */ static void loadLibraryWithPath(String libName, ClassLoader loader, String libraryPath) { return; } /** * Sets the assertion status of the class with the specified name. * <p> * <strong>Note: </strong>This method does nothing in the Android reference * implementation. * </p> * * @param cname * the name of the class for which to set the assertion status. * @param enable * the new assertion status. * @since Android 1.0 */ public void setClassAssertionStatus(String cname, boolean enable) { return; } /** * Sets the assertion status of the package with the specified name. * <p> * <strong>Note: </strong>This method does nothing in the Android reference * implementation. * </p> * * @param pname * the name of the package for which to set the assertion status. * @param enable * the new assertion status. * @since Android 1.0 */ public void setPackageAssertionStatus(String pname, boolean enable) { return; } /** * Sets the default assertion status for this class loader. * <p> * <strong>Note: </strong>This method does nothing in the Android reference * implementation. * </p> * * @param enable * the new assertion status. * @since Android 1.0 */ public void setDefaultAssertionStatus(boolean enable) { return; } /** * Sets the default assertion status for this class loader to {@code false} * and removes any package default and class assertion status settings. * <p> * <strong>Note:</strong> This method does nothing in the Android reference * implementation. * </p> * * @since Android 1.0 */ public void clearAssertionStatus() { return; } /** * Returns the assertion status of the named class Returns the assertion * status of the class or nested class if it has been set. Otherwise returns * the assertion status of its package or superpackage if that has been set. * Otherwise returns the default assertion status. Returns 1 for enabled and * 0 for disabled. * * @return the assertion status. * @param cname * the name of class. */ boolean getClassAssertionStatus(String cname) { return false; } /** * Returns the assertion status of the named package Returns the assertion * status of the named package or superpackage if that has been set. * Otherwise returns the default assertion status. Returns 1 for enabled and * 0 for disabled. * * @return the assertion status. * @param pname * the name of package. */ boolean getPackageAssertionStatus(String pname) { return false; } /** * Returns the default assertion status * * @return the default assertion status. */ boolean getDefaultAssertionStatus() { return false; } } /* * Provides a helper class that combines two existing URL enumerations into one. * It is required for the getResources() methods. Items are fetched from the * first enumeration until it's empty, then from the second one. */ class TwoEnumerationsInOne implements Enumeration<URL> { private Enumeration<URL> first; private Enumeration<URL> second; public TwoEnumerationsInOne(Enumeration<URL> first, Enumeration<URL> second) { this.first = first; this.second = second; } public boolean hasMoreElements() { return first.hasMoreElements() || second.hasMoreElements(); } public URL nextElement() { if (first.hasMoreElements()) { return first.nextElement(); } else { return second.nextElement(); } } } /** * Provides an explicit representation of the boot class loader. It sits at the * head of the class loader chain and delegates requests to the VM's internal * class loading mechanism. */ class BootClassLoader extends ClassLoader { static BootClassLoader instance; public static BootClassLoader getInstance() { if (instance == null) { instance = new BootClassLoader(); } return instance; } public BootClassLoader() { super(null, true); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { return VMClassLoader.loadClass(name, false); } @Override protected URL findResource(String name) { return VMClassLoader.getResource(name); } @SuppressWarnings("unused") @Override protected Enumeration<URL> findResources(String resName) throws IOException { Enumeration<URL> result = VMClassLoader.getResources(resName); // VMClassLoader doesn't keep the contract for getResources() if (result == null) { result = EmptyEnumeration.getInstance(); } return result; } /** * Returns package information for the given package. Unfortunately, the * Android BootClassLoader doesn't really have this information, and as a * non-secure ClassLoader, it isn't even required to, according to the spec. * Yet, we want to provide it, in order to make all those hopeful callers of * {@code myClass.getPackage().getName()} happy. Thus we construct a Package * object the first time it is being requested and fill most of the fields * with dummy values. The Package object is then put into the ClassLoader's * Package cache, so we see the same one next time. We don't create Package * objects for null arguments or for the default package. * <p> * There a limited chance that we end up with multiple Package objects * representing the same package: It can happen when when a package is * scattered across different JAR files being loaded by different * ClassLoaders. Rather unlikely, and given that this whole thing is more or * less a workaround, probably not worth the effort. */ @Override protected Package getPackage(String name) { if (name != null && !"".equals(name)) { synchronized (this) { Package pack = super.getPackage(name); if (pack == null) { pack = definePackage(name, "Unknown", "0.0", "Unknown", "Unknown", "0.0", "Unknown", null); } return pack; } } return null; } @Override public URL getResource(String resName) { return findResource(resName); } @Override protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException { Class<?> clazz = findLoadedClass(className); if (clazz == null) { clazz = findClass(className); } return clazz; } @Override public Enumeration<URL> getResources(String resName) throws IOException { return findResources(resName); } } /** * TODO Open issues - Missing / empty methods - Signer stuff - Protection * domains - Assertions */
DexClassLoader.java
/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package dalvik.system; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.zip.ZipFile; import java.net.MalformedURLException; import dalvik.system.DexFile; /** * Provides a simple {@link ClassLoader} implementation that operates on a * list of jar/apk files with classes.dex entries. The directory that * holds the optimized form of the files is specified explicitly. This * can be used to execute code not installed as part of an application. * * The best place to put the optimized DEX files is in app-specific * storage, so that removal of the app will automatically remove the * optimized DEX files. If other storage is used (e.g. /sdcard), the * app may not have an opportunity to remove them. */ public class DexClassLoader extends ClassLoader { private static final boolean VERBOSE_DEBUG = false; /* constructor args, held for init */ private final String mRawDexPath; private final String mRawLibPath; private final String mDexOutputPath; private boolean mInitialized; /* * Parallel arrays for jar/apk files. * * (could stuff these into an object and have a single array; * improves clarity but adds overhead) */ private File[] mFiles; // source file Files, for rsrc URLs private ZipFile[] mZips; // source zip files, with resources private DexFile[] mDexs; // opened, prepped DEX files /* * Native library path. */ private String[] mLibPaths; /** * Creates a {@code DexClassLoader} that finds interpreted and native * code. Interpreted classes are found in a set of DEX files contained * in Jar or APK files. * * The path lists are separated using the character specified by * the "path.separator" system property, which defaults to ":". * * @param dexPath * the list of jar/apk files containing classes and resources * @param dexOutputDir * directory where optimized DEX files should be written * @param libPath * the list of directories containing native libraries; may be null * @param parent * the parent class loader */ public DexClassLoader(String dexPath, String dexOutputDir, String libPath, ClassLoader parent) { super(parent); if (dexPath == null || dexOutputDir == null) throw new NullPointerException(); mRawDexPath = dexPath; mDexOutputPath = dexOutputDir; mRawLibPath = libPath; } /** * Complete initialization on first use of the class loader. */ private synchronized void ensureInit() { if (mInitialized) { return; } String[] dexPathList; mInitialized = true; dexPathList = mRawDexPath.split(":"); int length = dexPathList.length; //System.out.println("DexClassLoader: " + dexPathList); mFiles = new File[length]; mZips = new ZipFile[length]; mDexs = new DexFile[length]; /* open all Zip and DEX files up front */ for (int i = 0; i < length; i++) { //System.out.println("My path is: " + dexPathList[i]); File pathFile = new File(dexPathList[i]); mFiles[i] = pathFile; if (pathFile.isFile()) { try { mZips[i] = new ZipFile(pathFile); } catch (IOException ioex) { // expecting IOException and ZipException System.out.println("Failed opening '" + pathFile + "': " + ioex); //ioex.printStackTrace(); } /* we need both DEX and Zip, because dex has no resources */ try { String outputName = generateOutputName(dexPathList[i], mDexOutputPath); mDexs[i] = DexFile.loadDex(dexPathList[i], outputName, 0); } catch (IOException ioex) { // might be a resource-only zip System.out.println("Failed loadDex '" + pathFile + "': " + ioex); } } else { if (VERBOSE_DEBUG) System.out.println("Not found: " + pathFile.getPath()); } } /* * Prep for native library loading. */ String pathList = System.getProperty("java.library.path", "."); String pathSep = System.getProperty("path.separator", ":"); String fileSep = System.getProperty("file.separator", "/"); if (mRawLibPath != null) { if (pathList.length() > 0) { pathList += pathSep + mRawLibPath; } else { pathList = mRawLibPath; } } mLibPaths = pathList.split(pathSep); length = mLibPaths.length; // Add a '/' to the end so we don't have to do the property lookup // and concatenation later. for (int i = 0; i < length; i++) { if (!mLibPaths[i].endsWith(fileSep)) mLibPaths[i] += fileSep; if (VERBOSE_DEBUG) System.out.println("Native lib path " +i+ ": " + mLibPaths[i]); } } /** * Convert a source path name and an output directory to an output * file name. */ private static String generateOutputName(String sourcePathName, String outputDir) { StringBuilder newStr = new StringBuilder(80); /* start with the output directory */ newStr.append(outputDir); if (!outputDir.endsWith("/")) newStr.append("/"); /* get the filename component of the path */ String sourceFileName; int lastSlash = sourcePathName.lastIndexOf("/"); if (lastSlash < 0) sourceFileName = sourcePathName; else sourceFileName = sourcePathName.substring(lastSlash+1); /* * Replace ".jar", ".zip", whatever with ".dex". We don't want to * use ".odex", because the build system uses that for files that * are paired with resource-only jar files. If the VM can assume * that there's no classes.dex in the matching jar, it doesn't need * to open the jar to check for updated dependencies, providing a * slight performance boost at startup. The use of ".dex" here * matches the use on files in /data/dalvik-cache. */ int lastDot = sourceFileName.lastIndexOf("."); if (lastDot < 0) newStr.append(sourceFileName); else newStr.append(sourceFileName, 0, lastDot); newStr.append(".dex"); if (VERBOSE_DEBUG) System.out.println("Output file will be " + newStr.toString()); return newStr.toString(); } /** * Finds a class. This method is called by {@code loadClass()} after the * parent ClassLoader has failed to find a loaded class of the same name. * * @param name * The name of the class to search for, in a human-readable form * like "java.lang.String" or "java.net.URLClassLoader$3$1". * @return the {@link Class} object representing the class * @throws ClassNotFoundException * if the class cannot be found */ @Override protected Class<?> findClass(String name) throws ClassNotFoundException { ensureInit(); if (VERBOSE_DEBUG) System.out.println("DexClassLoader " + this + ": findClass '" + name + "'"); byte[] data = null; int length = mFiles.length; for (int i = 0; i < length; i++) { if (VERBOSE_DEBUG) System.out.println(" Now searching: " + mFiles[i].getPath()); if (mDexs[i] != null) { String slashName = name.replace('.', '/'); Class clazz = mDexs[i].loadClass(slashName, this); if (clazz != null) { if (VERBOSE_DEBUG) System.out.println(" found"); return clazz; } } } throw new ClassNotFoundException(name + " in loader " + this); } /** * Finds a resource. This method is called by {@code getResource()} after * the parent ClassLoader has failed to find a loaded resource of the same * name. * * @param name * The name of the resource to find * @return the location of the resource as a URL, or {@code null} if the * resource is not found. */ @Override protected URL findResource(String name) { ensureInit(); int length = mFiles.length; for (int i = 0; i < length; i++) { File pathFile = mFiles[i]; ZipFile zip = mZips[i]; if (zip.getEntry(name) != null) { if (VERBOSE_DEBUG) System.out.println(" found " + name + " in " + pathFile); try { // File.toURL() is compliant with RFC 1738 in always // creating absolute path names. If we construct the // URL by concatenating strings, we might end up with // illegal URLs for relative names. return new URL("jar:" + pathFile.toURL() + "!/" + name); } catch (MalformedURLException e) { throw new RuntimeException(e); } } } if (VERBOSE_DEBUG) System.out.println(" resource " + name + " not found"); return null; } /** * Finds a native library. This method is called after the parent * ClassLoader has failed to find a native library of the same name. * * @param libname * The name of the library to find * @return the complete path of the library, or {@code null} if the library * is not found. */ @Override protected String findLibrary(String libname) { ensureInit(); String fileName = System.mapLibraryName(libname); for (int i = 0; i < mLibPaths.length; i++) { String pathName = mLibPaths[i] + fileName; File test = new File(pathName); if (test.exists()) { if (VERBOSE_DEBUG) System.out.println(" found " + libname); return pathName; } } if (VERBOSE_DEBUG) System.out.println(" library " + libname + " not found"); return null; } /** * Returns package information for the given package. Unfortunately, the * DexClassLoader doesn't really have this information, and as a non-secure * ClassLoader, it isn't even required to, according to the spec. Yet, we * want to provide it, in order to make all those hopeful callers of * <code>myClass.getPackage().getName()</code> happy. Thus we construct a * Package object the first time it is being requested and fill most of the * fields with dummy values. The Package object is then put into the * ClassLoader's Package cache, so we see the same one next time. We don't * create Package objects for null arguments or for the default package. * <p> * There a limited chance that we end up with multiple Package objects * representing the same package: It can happen when when a package is * scattered across different JAR files being loaded by different * ClassLoaders. Rather unlikely, and given that this whole thing is more or * less a workaround, probably not worth the effort. * * @param name * the name of the class * @return the package information for the class, or {@code null} if there * is not package information available for it */ @Override protected Package getPackage(String name) { if (name != null && !"".equals(name)) { synchronized(this) { Package pack = super.getPackage(name); if (pack == null) { pack = definePackage(name, "Unknown", "0.0", "Unknown", "Unknown", "0.0", "Unknown", null); } return pack; } } return null; } }
PathClassLoader.java
/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package dalvik.system; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.InputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.NoSuchElementException; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.net.MalformedURLException; import dalvik.system.DexFile; /** * Provides a simple {@link ClassLoader} implementation that operates on a list * of files and directories in the local file system, but does not attempt to * load classes from the network. Android uses this class for its system class * loader and for its application class loader(s). * * @since Android 1.0 */ public class PathClassLoader extends ClassLoader { private final String path; private final String libPath; private boolean initialized; private String[] mPaths; private File[] mFiles; private ZipFile[] mZips; private DexFile[] mDexs; private String[] mLibPaths; /** * Creates a {@code PathClassLoader} that operates on a given list of files * and directories. This method is equivalent to calling * {@link #PathClassLoader(String, String, ClassLoader)} with a * {@code null} value for the second argument (see description there). * * @param path * the list of files and directories * * @param parent * the parent class loader */ public PathClassLoader(String path, ClassLoader parent) { this(path, null, parent); } /** * Creates a {@code PathClassLoader} that operates on two given lists of * files and directories. The entries of the first list should be one of the * following: * <ul> * <li>Directories containing classes or resources. * <li>JAR/ZIP/APK files, possibly containing a "classes.dex" file. * <li>"classes.dex" files. * </ul> * The entries of the second list should be directories containing native * library files. Both lists are separated using the character specified by * the "path.separator" system property, which, on Android, defaults to ":". * * @param path * the list of files and directories containing classes and * resources * * @param libPath * the list of directories containing native libraries * * @param parent * the parent class loader */ public PathClassLoader(String path, String libPath, ClassLoader parent) { super(parent); if (path == null) throw new NullPointerException(); this.path = path; this.libPath = libPath; } private synchronized void ensureInit() { if (initialized) { return; } initialized = true; mPaths = path.split(":"); int length = mPaths.length; //System.out.println("PathClassLoader: " + mPaths); mFiles = new File[length]; mZips = new ZipFile[length]; mDexs = new DexFile[length]; boolean wantDex = System.getProperty("android.vm.dexfile", "").equals("true"); /* open all Zip and DEX files up front */ for (int i = 0; i < length; i++) { //System.out.println("My path is: " + mPaths[i]); File pathFile = new File(mPaths[i]); mFiles[i] = pathFile; if (pathFile.isFile()) { try { mZips[i] = new ZipFile(pathFile); } catch (IOException ioex) { // expecting IOException and ZipException //System.out.println("Failed opening '" + pathFile + "': " + ioex); //ioex.printStackTrace(); } if (wantDex) { /* we need both DEX and Zip, because dex has no resources */ try { mDexs[i] = new DexFile(pathFile); } catch (IOException ioex) {} } } } /* * Prep for native library loading. */ String pathList = System.getProperty("java.library.path", "."); String pathSep = System.getProperty("path.separator", ":"); String fileSep = System.getProperty("file.separator", "/"); if (libPath != null) { if (pathList.length() > 0) { pathList += pathSep + libPath; } else { pathList = libPath; } } mLibPaths = pathList.split(pathSep); length = mLibPaths.length; // Add a '/' to the end so we don't have to do the property lookup // and concatenation later. for (int i = 0; i < length; i++) { if (!mLibPaths[i].endsWith(fileSep)) mLibPaths[i] += fileSep; if (false) System.out.println("Native lib path: " + mLibPaths[i]); } } /** * Finds a class. This method is called by {@code loadClass()} after the * parent ClassLoader has failed to find a loaded class of the same name. * * @param name * The "binary name" of the class to search for, in a * human-readable form like "java.lang.String" or * "java.net.URLClassLoader$3$1". * @return the {@link Class} object representing the class * @throws ClassNotFoundException * if the class cannot be found */ @Override protected Class<?> findClass(String name) throws ClassNotFoundException { ensureInit(); //System.out.println("PathClassLoader " + this + ": findClass '" + name + "'"); byte[] data = null; int length = mPaths.length; for (int i = 0; i < length; i++) { //System.out.println("My path is: " + mPaths[i]); if (mDexs[i] != null) { Class clazz = mDexs[i].loadC发表评论
相关推荐
在Java虚拟机(JVM)中,类加载器(ClassLoader)是至关重要的组成部分,它负责查找和加载类的字节码文件。理解ClassLoader的工作机制对于深入掌握Java应用程序的运行至关重要。这里我们将详细讨论ClassLoader的运行...
《深入理解ClassLoader工作机制》 Java虚拟机(JVM)中的ClassLoader是负责加载类到内存中的核心组件。它不仅承担着将字节码转换为可执行对象的重任,还参与了类生命周期的各个阶段,包括加载、验证、准备、解析、...
在Java中,Classloader是加载类的关键组件,它负责查找、加载和初始化字节码文件。自定义Classloader允许开发者根据特定需求定制类的加载逻辑,例如加密类文件、隔离不同版本的库或者动态加载代码。本文将深入探讨...
在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中,使得程序能够执行。本示例"ClassLoader小例子"将深入探讨这个概念,并通过一个具体的程序来演示其工作原理。下面我们...
Java ClassLoader是Java运行时系统的关键但经常被忽视的组件,负责在运行时查找和加载类文件。通过创建自定义ClassLoader,你可以定制JVM,使类文件的引入方式完全重新定义,这提供了很多实用和有趣的可能。这篇教程...
Java ClassLoader机制是Java虚拟机(JVM)中一个至关重要的组成部分,它的主要任务是将类的.class文件加载到JVM中,使得程序能够运行。ClassLoader不仅负责类的加载,还涉及类的验证、初始化等一系列过程。理解...
在Java编程语言中,`ClassLoader`是一个至关重要的组件,它负责加载类到JVM(Java虚拟机)中。本文将深入探讨`ClassLoader`的工作原理、加密解密应用程序以及如何防止类被反编译。 首先,让我们理解`ClassLoader`的...
在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中。理解ClassLoader的工作原理以及如何定制它,对于深入学习Java的运行机制和进行高级应用开发具有重要意义。本篇文章将...
在Java世界中,类加载器(ClassLoader)是关键的组件之一,它负责将类的字节码文件(.class)从文件系统或网络中加载到Java虚拟机(JVM)中,使得程序能够运行。本篇文章将深入探讨ClassLoader的关系网络以及如何...
《ClassLoader详解》 Java应用程序的运行离不开类的加载,而ClassLoader正是这个过程的关键角色。它负责将类的字节码加载到Java虚拟机(JVM)中并转换为可执行的Java对象。深入理解ClassLoader的工作原理对于优化...
Java ClassLoader机制是Java运行时环境中的核心组件之一,它负责加载类到JVM(Java虚拟机)中,使得程序能够执行。理解ClassLoader的工作原理对于优化应用性能、处理类加载问题以及实现自定义加载器至关重要。 首先...
在Java编程语言中,ClassLoader是核心组件之一,它负责加载类到JVM(Java虚拟机)中执行。本文将深入探讨ClassLoader的工作原理和类加载机制,帮助开发者理解这个至关重要的概念。 1. 类加载机制概述 Java的类加载...
### 深入了解Java ClassLoader与Bytecode #### 一、Java ClassLoader概述 **1.1 什么是ClassLoader** 在传统的C/C++程序中,整个程序被编译成一个可执行文件,运行时一次性加载到内存中。而Java程序则不同,它是...
在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中执行。这篇测试主要探讨了ClassLoader的工作原理及其在实际应用中的使用。通过阅读给出的博文链接,我们可以深入理解...
### Java ClassLoader与ClassPath详解 #### 一、概述 在Java编程中,类加载机制是十分关键的一个环节。类加载器(`ClassLoader`)负责将编译后的`.class`文件加载到Java虚拟机(JVM)中执行,而类路径(`ClassPath...
Java的类加载器(ClassLoader)体系结构是JVM(Java虚拟机)中至关重要的一部分,它负责将类的字节码转换为运行时的类实例。本文将深入探讨启动类加载器、扩展类加载器、系统类加载器以及用户自定义类加载器,同时还...
破解java加密的ClassLoader.java,在classloader植入破解代码