JVM如何判断类相同

 JVM根据两个方面判断:一是类的全称;另一个是类加载器.

类的全称是相同的,那类加载器是否相同呢?

即使类的全称相同,而使用的加载器不同,那Class对象也是不同的.

 

package com.test;

public class TestClass {
	
	public static void main(String[] args){

		try {
			// 动态加载类、测试Class.forName()
			Class testTypeForName = Class.forName("com.test.TestClassType");
			System.out.println("testForName---" + testTypeForName);
			// 测试类加载器
			System.out.println("forName形式的加载器--"
					+ testTypeForName.getClassLoader());

			System.out.println();
			
			try {
				TestClassType tp = (TestClassType) testTypeForName.newInstance();
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println("forName形式的加载器--"
					+ testTypeForName.getClassLoader());
			System.out.println();
			
			// 测试类名.class
			Class testTypeClass = TestClassType.class;
			System.out.println("testTypeClass---" + testTypeClass);
			System.out.println("class形式的加载器---"
					+ testTypeClass.getClassLoader());

			System.out.println();
			
			// 测试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("----非静态的参数初始化---");
	}
}

 

结果:

---静态参数初始化---
testForName---class com.test.TestClassType
forName形式的加载器--sun.misc.Launcher$AppClassLoader@6b97fd

----非静态的参数初始化---
----构造函数---
forName形式的加载器--sun.misc.Launcher$AppClassLoader@6b97fd

testTypeClass---class com.test.TestClassType
class形式的加载器---sun.misc.Launcher$AppClassLoader@6b97fd

----非静态的参数初始化---
----构造函数---
testGetClass---class com.test.TestClassType
getClass形式的加载器--sun.misc.Launcher$AppClassLoader@6b97fd

 

观察结果发现:三种形式的加载器是相同的.

jvm中类相同的条件:类加载器实例+包名+类名

而java中相同的类: 包名+类名

 

一.什么时候用Class.forName()?

先来个热身,给你一个字符串变量,它代表一个类的包名和类名,你怎么实例化它?你第一想到的肯定是new,但是注意一点:

A a = (A)Class.forName(“pacage.A”).newInstance();

这和你 A a = new A(); 是一样的效果。

现在言归正传。

动态加载和创建Class 对象,比如想根据用户输入的字符串来创建对象时需要用到:

String str = “用户输入的字符串” ;

Class t = Class.forName(str);

t.newInstance();

在初始化一个类,生成一个实例的时候,newInstance()方法和new关键字除了一个是方法,一个是关键字外,最主要有什么区别?

它们的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类

那么为什么会有两种创建对象方式?这主要考虑到软件的可伸缩、可扩展和可重用等软件设计思想。

从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。但是使用newInstance()方法的时候,就必须保证:

1、这个类已经加载;

2、这个类已经连接了。

而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载 java API的那个加载器。

现在可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。

这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了一种降耦的手段。

二.new 和Class.forName()有什么区别?

其实上面已经说到一些了,这里来做个总结:

首先,newInstance( )是一个方法,而new是一个关键字

其次,Class下的newInstance()的使用有局限,因为它生成对象只能调用无参的构造函数而使用 new关键字生成对象没有这个限制。

简言之:

newInstance(): 弱类型,低效率,只能调用无参构造。

new: 强类型,相对高效,能调用任何public构造。

Class.forName(“”)返回的是类。

Class.forName(“”).newInstance()返回的是object 。

三.为什么在加载数据库驱动包的时候有用的是Class.forName( ),却没有调用newInstance( )?

在Java开发特别是数据库开发中,经常会用到Class.forName( )这个方法。

 有数据库开发经验朋友会发现,为什么在我们加载数据库驱动包的时候有的却没有调用newInstance( )方法呢?即有的jdbc连接数据库的写法里是Class.forName(xxx.xx.xx);而有一 些:Class.forName(xxx.xx.xx).newInstance(),为什么会有这两种写法呢?

   刚才提到,Class.forName("");的作用是要求JVM查找并加载指定的类,如果在类中有静态初始化器的话,JVM必然会执行该类的静态代码 段。而在JDBC规范中明确要求这个Driver类必须向DriverManager注册自己,即任何一个JDBC Driver的 Driver类的代码都必须类似如下:

  public class MyJDBCDriver implements Driver {

   static {

     DriverManager.registerDriver(new MyJDBCDriver());

  }

  }

 既然在静态初始化器的中已经进行了注册,所以我们在使用JDBC时只需要Class.forName(XXX.XXX);就可以了。

 

贴出Proxool 连接池的静态初始化方法:

public class ProxoolDriver implements Driver {

    private static final Log LOG = LogFactory.getLog(ProxoolDriver.class);

    static {
        try {
            DriverManager.registerDriver(new ProxoolDriver());
        } catch (SQLException e) {
            System.out.println(e.toString());
        }
    }
}

 

...

猜你喜欢

转载自uule.iteye.com/blog/2420077