JVM中class对象加载方式

1 class对象详解

java中把生成Class对象和实例对象弄混了,更何况生成Class对象和生成instance都有多种方式。所以只有弄清其中的原理,才可以深入理解。首先要生成Class对象,然后再生成Instance。那Class对象的生成方式有哪些呢,以及其中是如何秘密生成的呢?
Class对象的生成方式如下:

  1. Class.forName("类名字符串") (注意:类名字符串必须是全称,包名+类名)
  2. 类名.class
  3. 实例对象.getClass()

通过一段小程序,来观察一下Class对象的生成的原理。

  public class TestClass {    
public  static void main(String[] args)  {    
try {    
//测试Class.forName()  
  Class testTypeForName=Class.forName("TestClassType");          
  System.out.println("testForName---"+testTypeForName);  
  //测试类名.class  
  Class testTypeClass=TestClassType.class;  
  System.out.println("testTypeClass---"+testTypeClass);  
  //测试Object.getClass()  
  TestClassType testGetClass= new TestClassType();  
  System.out.println("testGetClass---"+testGetClass.getClass());  
  
 } catch (ClassNotFoundException e) {  
  // TODO Auto-generated catch block  
  e.printStackTrace();  
  }  
}  
  
}  
   class TestClassType{  
  //构造函数  
  public TestClassType(){  
  System.out.println("----构造函数---");  
  }  
  //静态的参数初始化  
  static{  
  System.out.println("---静态的参数初始化---");  
  }  
  
//非静态的参数初始化  
  {  
  System.out.println("----非静态的参数初始化---");  
  }          
  }  

测试的结果如下:
---静态的参数初始化---
testForName---class TestClassType
testTypeClass---class TestClassType
----非静态的参数初始化---
----构造函数---
testGetClass---class TestClassType

根据结果可以发现,三种生成的Class对象一样的。并且三种生成Class对象只打印一次静态的参数初始化
我们知道,静态的方法属性初始化,是在加载类的时候初始化。而非静态方法属性初始化,是new类实例对象的时候加载。
因此,这段程序说明,三种方式生成Class对象,其实只有一个Class对象。在生成Class对象的时候,首先判断内存中是否已经加载。

所以,生成Class对象的过程其实是如此的:当我们编写一个新的java类时,JVM就会帮我们编译成class对象,存放在同名的.class文件中。在运行时,当需要生成这个类的对象,JVM就会检查此类是否已经装载内存中。若是没有装载,则把.class文件装入到内存中。若是装载,则根据class文件生成实例对象。

2 Class.forName和ClassLoader.loadClass区别

2.1 jvm加载class步骤

Javaclass是如何加载到JVM中的:
class加载到JVM中有三个步骤:

  • 装载:(loading)找到class对应的字节码文件。
  • 连接:(linking)将对应的字节码文件读入到JVM中。
  • 初始化:(initializing)对class做相应的初始化动作。

2.2 两种方式的详细方法

Java中两种加载classJVM中的方式

  • Class.forName("className");
    其实这种方法调运的是:Class.forName(className, true,ClassLoader.getCallerClassLoader())方法
    参数一:className,需要加载的类的名称。
    参数二:true,是否对class进行初始化(需要initialize)
    参数三:classLoader,对应的类加载器

  • ClassLoader.laodClass("className");
    其实这种方法调运的是:ClassLoader.loadClass(name, false)方法
    参数一:name,需要加载的类的名称
    参数二:false,这个类加载以后是否需要去连接(不需要linking)

2.3 两种方式的区别

forName("")得到的class是已经初始化完成的
loadClass("")得到的class是还没有连接的
一般情况下,这两个方法效果一样,都能装载Class
但如果程序依赖于Class是否被初始化,就必须用Class.forName(name)了。

2.4 举例说明他们各自的使用方法

java使用JDBC连接数据库时候,我们首先需要加载数据库驱动。

Class.forName("com.mysql.jdbc.Driver");//通过这种方式将驱动注册到驱动管理器上
Connection conn = DriverManager.getConnection("url","userName","password");//通过驱动管理器获得相应的连接

查看com.mysql.jdbc.Driver源码:

public class Driver extends NonRegisteringDriver
  implements java.sql.Driver
{
    //注意,这里有一个static的代码块,这个代码块将会在class初始化的时候执行
  static
  {
    try
    {
        //将这个驱动Driver注册到驱动管理器上
      DriverManager.registerDriver(new Driver());
    } catch (SQLException E) {
      throw new RuntimeException("Can't register driver!");
    }
  }
}

Class.forName("com.mysql.jdbc.Driver")方法以后,他会进行class的初始化,执行static代码块。
也就是说class初始化以后,就会将驱动注册到DriverManageer上,之后才能通过DriverManager去获取相应的连接。
但是要是我们使用ClassLoader.loadClass(com.mysql.jdbc.Driver)的话,不会link,更也不会初始化class。相应的就不会回将Driver注册到DriverManager上面,所以肯定不能通过DriverManager获取相应的连接。
附录:JVM加载class文件原理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值