java程序从源码到运行所经历的过程:
*.java--->编译成*.class--->加载到内存
*.java经过javac.exe编译成*.class,经过类加载器加载到内存(*.class文件被解析并封装成Class类型的一个实例对象),然后这个Class类型的对象 产生无数 具体类型实例对象
由上面过程我们可以得知:对象被new时,其实是从一个 描述者类信息的Class实例对象生成的,即通过它可以访问方法区中的被解析后的class文件的数据结构,它里面有好多引用地址,通过这些地址就能找到方法区中的类成员(属性和方法)。
一些反射与Class文件格式的小问题
(以下摘自http://blog.csdn.net/providence2712/article/details/8708005)
Class文件格式是能被Java虚拟机读取的一种文件格式。
Java编译器可以把Java代码编译成存储字节码的Class文件,但也有一大批可以在Java虚拟机上运行的语言,如Groovy,JRuby,Jython...... 。JRuby等其他语言的编译器一样可以把程序代码编译成Class文件,虚拟机并不关心Class文件的来源是什么语言,所以Class文件格式是独立存在的。只要符合Class文件应有的结构就可以在Java虚拟机种运行。而且Class文件广义来讲应该就是一串二进制字节流,无论以何种形式存在。不一定要是存在磁盘上的.class文件这个形式。
问题一:
那磁盘上的.class文件(Class文件)和内存中的字节码文件对象(Class文件对象)是不是一回事呢?
肯定不是一回事。
解释:
① Java编译器把代码编译成存储字节码的.class文件(Class文件)。现在还不是内存中的对象。
② 然后,虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型(现在才是字节码文件对象)。这其实就是类加载,最终产生的是Heap中的代表该类的java.lang.Class对象。
③ 类的生命周期一共有7个阶段。这里只介绍第一个阶段“加载”阶段,虚拟机需要完成的三件事情:
1.通过一个类的全限定名来获取定义此类的二进制字节流。
2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。(Heap中的Class对象就是封装了方法区中的类信息)
3.在Java堆中生成一个代表这个类的java.lang.Class对象,作为方法区这些数据的访问入口。
④ 例如:磁盘上有个Person.class的Class文件(字节码文件)要变成Java
中可用的Person类型是需要经历虚拟机的类加载机制的。变成了Person类型(一种Class文件对象)才能用new Person()创建对象。
所以说Class文件和Class文件对象(字节码文件对象)是两回事。
问题二:
有人问我说.java和.class文件它们有什么区别?
我回答说没什么太大的区别。它们语义上都是相同的,所以本质上表达的东西是相同的。只不过.java文件是让人看的。.class文件是给虚拟机看的。当然,最终通过虚拟机给处理器看。字节码是一种程序编译后的中间存储格式,来达到平台无关性的目的。
下面是Java中Class类的由来。
Public final class Class<T>
{
...
}
大家知道我们写的类都是从现实生活中抽象而来,对我们程序员来说抽象是一个很重要的概念。
例一:现实生活中的人这类事物很复杂。我们就抽象出一个Java中的类来描述它。所以我们抽象出来的Person类(Person.java Person.class)在经过Java中的类加载机制后成为Java中的一个类型。
例二:那现实生活中的字节码文件(Class文件)也很复杂,所以我们也可以抽象出一个类来描述它,那就是Java中定义的Class类。(请注意区分Class文件格式 和 Java中定义的Class类)
下面的内容只是打个比喻增强大家的理解,但表述不准确。
假设Java中的Class类有N个不同的构造函数,能构造出各种类型。
下面的内容只是打个比喻增强大家的理解,但不是很准确。
我们一直说类(.java .class)就是创建对象的图纸。那么Class类就是对这些图纸的抽象。
Class类就是描述所有图纸的类。
最后对Field,Method,Constructor,Package类的解释:
Class类是整个抽象类文件。但类文件中还有其他的组件。这些组件也有一定复杂性。Java就更进一步把那些组件也抽象成对应的类。
例如:汽车也是一个现实中的对象,但组成汽车对象的还有变速箱,发动机,悬挂系统等也是一个个对象。