今日查看java中Class对象的详解时遇到这个问题。
Class对象的创建有三种方式:
用测试类Test举例
1.
Class.forName("Test")
2.
Test.class
3.
new Test().getClass()
但是这三种方式的实现不一样。
public class test {public static void main(String[] args){try { //1.测试Class.forName() // Class testTypeForName=Class.forName("TestClassType"); // System.out.println("testForName---"+testTypeForName);//2.测试类名.class // Class testTypeClass=TestClassType.class; // System.out.println("testTypeClass---"+testTypeClass);//3.测试Object.getClass() // TestClassType testGetClass= new TestClassType(); // System.out.println("testGetClass---"+new TestClassType().getClass());} catch (Exception e) { // TODO Auto-generated catch blocke.printStackTrace();}} }class TestClassType{ //构造函数public TestClassType(){System.out.println("----构造函数---");}//静态的参数初始化static{System.out.println("---静态的参数初始化---");}//非静态的参数初始化{System.out.println("----非静态的参数初始化---");} }
依次打开三种注释掉的方式运行后得到的结果
1.
---静态的参数初始化---
testForName---class TestClassType
2.
testTypeClass---class TestClassType
3.
---静态的参数初始化---
----非静态的参数初始化---
----构造函数---
testGetClass---class TestClassType
第三种方式可能原来就知道这是一个类实例化的过程,但是对前两种创建Class类的方式原理不太了解。然后查了一下。
1.概述
Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数,属性和方法等,Java允许用户借由这个Class相关的元信息对象间接调用Class对象的功能。
虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。
2.工作机制
类装载器就是寻找类的字节码文件,并构造出类在JVM内部表示的对象组件。在Java中,类装载器把一个类装入JVM中,要经过以下步骤:
(1) 装载:查找和导入Class文件;
(2) 链接:把类的二进制数据合并到JRE中;
(a)校验:检查载入Class文件数据的正确性;
(b)准备:给类的静态变量分配存储空间;
(c)解析:将符号引用转成直接引用;
(3) 初始化:对类的静态变量,静态代码块执行初始化操作
Java程序可以动态扩展是由运行期动态加载和动态链接实现的;比如:如果编写一个使用接口的应用程序,可以等到运行时再指定其实际的实现(多态),解析过程有时候还可以在初始化之后执行;比如:动态绑定(多态);
在JVM加载类的时候,需要经过三个步骤,装载、链接、初始化。装载就是找到相应的class文件,读入JVM,初始化就不用说了,最主要就说说链接。
链接分三步,第一步是验证class是否符合规格,第二步是准备,就是为类变量分配内存同时设置默认初始值,第三步就是解析,而这步就是可选的。
Class类中的forName方法最后调用的方法
private static native Class<?> forName0(String name, boolean initialize,ClassLoader loader,Class<?> caller)throws ClassNotFoundException;
参数initialize应该是是否解析。
ClassLoader中的loadClass方法最后调用的方法
protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException
方法里面有这么一段
if (resolve) {resolveClass(c); }
参数resolve应该也是是否解析的标识。
所以最开始的.class就是没有解析,而Class.forName()方法是解析了。
参考资料:http://blog.csdn.net/yuebinghaoyuan/article/details/7244123
http://www.iteye.com/topic/83978