天天看点

Class.forName和ClassLoader的区别及Native关键字介绍

一  共同点

      都可对类进行加载,返回Class对象(不是实例对象,Class对象是将.class文件加载到内存中,实例对象就是通常我们所说的new Object())

二   区别

       Class 中有两个重要方法:

forName(String className)

 : 返回与带有给定字符串名的类或接口相关联的 

Class

 对象。

forName(String name, boolean initialize, ClassLoader loader)

 :   使用给定的类加载器,返回与带有给定字符串名的类或接口相关联的 

Class

 对象。    

源码如下(jdk1.6):

public static Class<?> forName(String paramString) throws ClassNotFoundException {
		return forName0(paramString, true, ClassLoader.getCallerClassLoader());
	}

	public static Class<?> forName(String paramString, boolean paramBoolean, ClassLoader paramClassLoader)
			throws ClassNotFoundException {
		if (paramClassLoader == null) {
			SecurityManager localSecurityManager = System.getSecurityManager();
			if (localSecurityManager != null) {
				ClassLoader localClassLoader = ClassLoader.getCallerClassLoader();//获取调用者类的加载器
				if (localClassLoader != null) {
					localSecurityManager.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
				}
			}
		}

		return forName0(paramString, paramBoolean, paramClassLoader);
	}

	private static native Class forName0(String paramString, boolean paramBoolean, ClassLoader paramClassLoader)
			throws ClassNotFoundException;
           

          只有 

initialize

 参数为 

true

 且以前未被初始化时,才初始化该类。

          调用 forName("X") 将导致命名为 X 的类被初始化。

          返回具有指定名的类的 

Class

 对象。

第一个方法等价于:

Class.forName(className, true, currentLoader)
           
其中类加载器通过下述方法获取,getCallerClassLoader方法返回--获得调用者类的加载器:
           

ClassLoader localClassLoader = ClassLoader.getCallerClassLoader();

故通常使用的Class.forName()除了将.class文件加载到内存中,还会对类进行初始化,执行static块中代码,如JDBC注册驱动。

ClassLoader中常用方法:

public Class<?> loadClass(String name) throwsClassNotFoundException:使用指定的 二进制名称来加载类。此方法使用与 loadClass(String, boolean) 方法相同的方式搜索类。Java 虚拟机调用它来分析类引用。调用此方法等效于调用 loadClass(name, false)。

protectedClass<?>loadClass(String name,boolean resolve) throwsClassNotFoundException :使用指定的 二进制名称来加载类。

此方法的默认实现将按以下顺序搜索类:
           

1、调用 

findLoadedClass(String)

 来检查是否已经加载类。 2、在父类加载器上调用 

loadClass

 方法。如果父类加载器为 null,则使用虚拟机的内置类加载器。 3、调用 

findClass(String)

 方法查找类。 如果使用上述步骤找到类,并且 resolve 标志为真,则此方法将在得到的 Class 对象上调用 

resolveClass(Class)

 方法。 鼓励用 ClassLoader 的子类重写 

findClass(String)

,而不是使用此方法。

源码如下(jdk1.6):

public Class<?> loadClass(String paramString) throws ClassNotFoundException {
		return loadClass(paramString, false);
	}

	protected synchronized Class<?> loadClass(String paramString, boolean paramBoolean) throws ClassNotFoundException {
		Class localClass = findLoadedClass(paramString);
		if (localClass == null) {
			try {
				if (this.parent != null)
					localClass = this.parent.loadClass(paramString, false);
				else {
					localClass = findBootstrapClassOrNull(paramString);
				}
			} catch (ClassNotFoundException localClassNotFoundException) {
			}
			if (localClass == null) {
				localClass = findClass(paramString);
			}
		}
		if (paramBoolean) {
			resolveClass(localClass);
		}
		return localClass;
	}
           

故ClassLoader只将加载类到内存中,不会对类进行初始化。

三  Native介绍

      Class中有个方法定义:加载由 

libname

 参数指定的系统库,最终被java native修饰的方法调用。

       private static native Class forName0(String paramString,boolean paramBoolean, ClassLoader paramClassLoader)

throws ClassNotFoundException;

       由此好奇该关键字的作用。

      JNI:提供若干的API实现了Java和其它预言的通信(主要C&C++),称为Java Native Interface (Java本地接口)。 

      native的方法:java不用自己实现,是由C/C++语言实现且被编译成DLL,System.loadLibrary()方法加载该系统库,最终java native修饰的方法可调用DLL。

      实际上java就是在不同的平台上调用不同的native方法实现对操作系统的访问的。