深入理解JVM-类加载及类加载器 (6)

2020年02月09日09:41:01 继续吧。--- 今天是周末。原来说的要加班。不加了。学习

类加载器的层次关系 public class MyTest13{ psvm{ ClassLoader classLoader = ClassLoader.getSystemClassLoader(); sout(classLoader); while (null != classLoader){ classLoader = classLoader.getParent(); sout(classLoader); } } } > 输出结果: > Task :MyTest13.main() sun.misc.Launcher$APPClassLoader 应用类加载器 sun.misc.Launcher$ExtClassLoader 扩展类加载器 null 根类加载器 //如何通过给定的字节码路径,打印出类的信息 public class MyTest14{ psvm{ //上下文类加载器是由当前的线程提供的 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); String resourceName = "com/erwa/jvm/MyTest13.class"; Enumeration<URL> urls = classLoader.getResources(resourceName); while(urls.hasMoreElements()){ URL url = urls.nextElement(); sout(url); // 输出结果为 资源在本机上的完整路径。 } } } 获得ClassLoader的途径

获得当前类的CLassLoader

clazz.getClassLoader();

获得当前线程上下文的ClassLoader

Thread.currnetThread().getContextClassLoader();

获得系统的ClassLoader

CLassLoader.getSystemClassLoader();

获得调用者的ClassLoader

DriberManager.getCallerClassLoader();

sun.misc.Launcher$APPClassLoader 应用类加载器 sun.misc.Launcher$ExtClassLoader 扩展类加载器 null 根类加载器 比如: Class<?> clazz = String.class; sout(clazz.getClassLoader()); //打印结果为 null . 因为是系统的类。 Class<?> clazz = MyTest14.class; sout(clazz.getClassLoader()); //打印结果为 APPClassLoader . 因为自定义的类。 ClassLoader类源码剖析 ClassLoader的Javadoc: java.lang public abstract class ClassLoader extends Object A class loader is an object that is responsible for loading classes. The class ClassLoader is an abstract class. Given the binary name of a class, a class loader should attempt to locate or generate data that constitutes a definition for the class. A typical strategy is to transform the name into a file name and then read a "class file" of that name from a file system. /* 一个类加载器是一个对象,用于加载类。 ClassLoader是一个抽象类,如果我们给了二进制的名字,ClassLoader应该尝试生成一些数据(构成了这个类定义的数据)。 一种典型的策略是将二进制名字转换成文件名字,然后从系统中读取这个文件。 */ Every Class object contains a reference to the ClassLoader that defined it. // 每一个Class对象都会包含 定义这个类的类加载器对象 Class objects for array classes are not created by class loaders, but are created automatically as required by the Java runtime. The class loader for an array class, as returned by Class.getClassLoader() is the same as the class loader for its element type; if the element type is a primitive type, then the array class has no class loader. Applications implement subclasses of ClassLoader in order to extend the manner in which the Java virtual machine dynamically loads classes. /* 数组类 比较特殊: 对于数组内的Class对象,并不是由类加载器创建的,而是由Java运行时根据需要自动创建的(其他类是由类加载器创建的)(数组类型不会导致类的初始化)。对于一个数组类的ClassLoader来说,返回结果是数组当中元素的结果是一样的。如果数组中的元素是原生类型的,那么此时数组类是没有类加载器的。 应用程序实现类装入器的子类,以扩展Java虚拟机动态加载类的方式。 */ - - - - -- - 数组类的类加载器举例: - - - -- - - public class MyTest15{ psvm{ String[] strings = new String[2]; sout(strings.getClass().getClassLoader()); // 输出结果为null ; 因为是String 的类加载器(此时的null代表根类加载器的类型); MyTest15[] mytest15 = new MyTest15[2]; sout(mytest15.getClass().getClassLoader());// 结果为 AppClassLoader ; 因为是自自定义的类 Integer[] integet = new Integer[2]; sout(integet.getClass().getClassLoader()); // 输出结果为null;因为是原生类型。(此时的null不代表根类加载器的类型,就是null) } } Class loaders may typically be used by security managers to indicate security domains. // 类加载器 会伴随着安全管理器来确保安全的。 The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machines built-in class loader, called the "bootstrap class loader", does not itself have a parent but may serve as the parent of a ClassLoader instance. /* ClassLoader使用双亲委托模型来寻找资源。ClassLoader的每一个实例都有一个关联的父的ClassLoader。当要求ClassLoader去需要资源时,ClassLoader在自己寻找资源之前,会将资源寻找委托给它的父ClassLoader。层层往上递进。虚拟机内荐的类加载器叫做启动类加载器,它本身是没有双亲的,但是它可以当做是其他类加载器的双亲。 */ Class loaders that support concurrent loading of classes are known as parallel capable class loaders and are required to register themselves at their class initialization time by invoking the ClassLoader.registerAsParallelCapable method. Note that the ClassLoader class is registered as parallel capable by default. However, its subclasses still need to register themselves if they are parallel capable. In environments in which the delegation model is not strictly hierarchical, class loaders need to be parallel capable, otherwise class loading can lead to deadlocks because the loader lock is held for the duration of the class loading process (see loadClass methods). /* 并行的ClassLoader注册。 支持类的并发加载的类加载器称为支持并行的类加载器,需要通过调用类加载器在类初始化时注册它们自己。registerAsParallelCapable方法。注意,默认情况下ClassLoader类被注册为支持并行的。但是,它的子类仍然需要注册它们自己,如果它们是并行的。在委托模型没有严格层次结构的环境中,类装入器需要具有并行能力,否则类装入可能会导致死锁,因为装入器锁在类装入过程期间一直持有(请参阅loadClass方法)。 */ Normally, the Java virtual machine loads classes from the local file system in a platform-dependent manner. For example, on UNIX systems, the virtual machine loads classes from the directory defined by the CLASSPATH environment variable. /* 通常情况下,jvm会从本地文件系统中去加载类。 例如在unix 上,jvm会从CLasspath环境变量定义的目录中去加载。 */ However, some classes may not originate from a file; they may originate from other sources, such as the network, or they could be constructed by an application. The method defineClass converts an array of bytes into an instance of class Class. Instances of this newly defined class can be created using Class.newInstance. /* 然而,,一些类并不是来源于文件。 如通过网络,动态代理等。 这种情况下,定义类会将字节数组转换成class的一个实例。这个新定义的实例可能通过Class.newInstance来创建。 */ The methods and constructors of objects created by a class loader may reference other classes. To determine the class(es) referred to, the Java virtual machine invokes the loadClass method of the class loader that originally created the class. /* 类加载器创建的对象的方法和构造函数可以引用其他类。为了确定引用的类,Java虚拟机调用最初创建类的类加载器的loadClass方法。 */ For example, an application could create a network class loader to download class files from a server. Sample code might look like: // 例如,应用程序可以创建一个网络类装入器来从服务器下载类文件。示例代码可能如下: ClassLoader loader = new NetworkClassLoader(host, port); Object main = loader.loadClass("Main", true).newInstance(); . . . The network class loader subclass must define the methods findClass and loadClassData to load a class from the network. Once it has downloaded the bytes that make up the class, it should use the method defineClass to create a class instance. A sample implementation is: //网络类加载器子类必须定义findClass和loadClassData方法,以便从网络加载类。一旦下载了构成类的字节,就应该使用defineClass方法来创建类实例。一个示例实现是: class NetworkClassLoader extends ClassLoader { String host; int port; public Class findClass(String name) { byte[] b = loadClassData(name); return defineClass(name, b, 0, b.length); } private byte[] loadClassData(String name) { // load the class data from the connection . . . } } Binary names // `二进制的名字` 介绍: Any class name provided as a String parameter to methods in ClassLoader must be a binary name as defined by The Java™ Language Specification. Examples of valid class names include: "java.lang.String" // 字符串的类 "javax.swing.JSpinner$DefaultEditor" // DefaultEditor是JSpinner的一个内部类 "java.security.KeyStore$Builder$FileBuilder$1" // FileBuilder里的第一个匿名内部类 "java.net.URLClassLoader$3$1" // URLClassLoader里的第三个匿名内部类中的第一个匿名内部类 自定义一个类加载器

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpszsp.html