TA的每日心情 | 开心 2021-3-12 23:18 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
上篇中,提到Class生成对象的原理,根据上篇的小例子,得出的结果程序中的Class对象是一样的,是只有一个Class对象.那JVM是如何判断这三个Class对象其实是一个Class对象呢? JVM根据两个方面判断:一是类的全称;另一个是类加载器. 根据上篇中的结果得出:类的全称是相同的.那类加载器是否相同呢?即使类的全称相同,而使用的加载器不同,那Class对象也是不同的.那我们继续上篇中的例子,看看所使用的加载器的结果如何呢?其中使用getClassLoad()方法.
- /**
- * @author: 梁焕月
- * 文件名:TestClass.java
- * 时间:2012-2-6上午10:01:52
- */
-
- public class TestClass {
- public static void main(String[] args){
-
- try {
- //测试Class.forName()
- Class testTypeForName=Class.forName("TestClassType");
- System.out.println("testForName---"+testTypeForName);
-
- //测试类加载器
- System.out.println("forName形式的加载器--"+testTypeForName.getClassLoader());
- //测试类名.class
- Class testTypeClass=TestClassType.class;
- System.out.println("testTypeClass---"+testTypeClass);
-
- //测试类加载器
- System.out.println(".class形式的加载器---"+testTypeClass.getClassLoader());
-
- //测试Object.getClass()
- TestClassType testGetClass= new TestClassType();
- System.out.println("testGetClass---"+testGetClass.getClass());
-
- //测试类加载器
- System.out.println("getClass形式的加载器--"+testGetClass.getClass().getClassLoader());
-
- } catch (ClassNotFoundException e) {
-
- // TODO Auto-generated catch block
-
- e.printStackTrace();
-
- }
-
- }
-
- }
-
- class TestClassType{
-
- //构造函数
- public TestClassType(){
- System.out.println("----构造函数---");
- }
-
- //静态的参数初始化
-
- static{
- System.out.println("---静态的参数初始化---");
-
- }
-
- //非静态的参数初始化
-
- {
-
- System.out.println("----非静态的参数初始化---");
-
- }
-
- }
复制代码 结果如下:
C:java>java TestClass
---静态的参数初始化---
testForName---class TestClassType
forName形式的加载器--sun.misc.Launcher$AppClassLoader@19821f
testTypeClass---class TestClassType
.class形式的加载器---sun.misc.Launcher$AppClassLoader@19821f
----非静态的参数初始化---
----构造函数---
testGetClass---class TestClassType
getClass形式的加载器--sun.misc.Launcher$AppClassLoader@19821f
观察结果发现:三种形式的加载器是相同的. 因此可以说明上篇例子中的三个方式生成的Class对象只有一个.同样也证明了上篇中Class对象生成的原理。JVM首先判断内存中是否已经加载该类。判断的依据就是此篇的介绍。 java中默认的有三种类型加载器。分别是:系统类加载器(应用类加载器)、扩展类加载器、引导类加载器。 例子已经测试了加载器类型是: sun.misc.Launcher$AppClassLoader@f4f44a,这个是系统类加载器。来看一下父类的加载器类型: //测试类加载器
System.out.println("forName形式的加载器--"+testTypeForName.getClassLoader()); //测试父类加载器
System.out.println("testTypeForName的父类加载器--"+testTypeForName.getClassLoader().getParent());
System.out.println("testTypeForName的父类的父类的加载器--"+testTypeForName.getClassLoader().getParent().getParent()); 输出的结果如下:
forName形式的加载器--sun.misc.Launcher$AppClassLoader@f4f44a
testTypeForName的父类加载器--sun.misc.Launcher$ExtClassLoader@1d256fa
testTypeForName的父类的父类的加载器--null 结果说明了,系统类加载器的父类是扩展类加载器,扩展类加载器的父类是引导类加载器。他们之间的关系如下: 我们分析三种加载器的使用场合。 1.系统类加载器(应用类加载器),这个加载器使用java实现,使用广泛,负责加载classPath中指定的类。
具体的使用场合是:加载classPath中指定的而扩展类加载器没有加载的类。若扩展类加载器加载了classPath中的类,则系统类加载器则没有机会加载。
用户定义的类一般都是系统类加载器加载的。
可以通过:ClassLoader.getSystemClassLoader()获得。 2.扩展类加载器。
它负责加载Java的标准扩展,一般使用Java实现的,负责加载jre/lib/ext中的类。和普通的类加载器一样。
可以通过:ClassLoader.getSystemClassLoader().getParent()获得。 3.引导类加载器。
它负责加载jdk中的系统类,是用C语言实现的。对于java程序无法获得它,像上文中获得扩展类加载器的父类加载器是null。像 String,Integer,Double类都是由引导类加载器加载的。
类加载机制的原理是双亲委派机制。
当加载一个类时,首先把机会让给父类,先让父类加载,若是父类中不能加载,才会自己再加载。(这是孝顺型的,先想到父类) 而那个Tomcat加载器则恰恰相反。 当加载一个类时,首先自己加载,自己加载不了,则再去找父类帮忙。(这个忘恩型的,先想到自己)
|
|