编译顺序
编译器 虚拟机虚拟机
java源文件*java>字节码*class>类装载器>执行引擎
一个class文件只能包含一个类或接口因此java文件中定义了多少类编译时就会生成多少class文件(内部类不算)
java程序可以选择两种方式访问底层系统由程序员选择
()通过java程序调用javaapi调用本地方法访问底层系统与平台无关
()通过java程序直接调用本地方法访问底层系统与平台相关
本地方法即操作系统提供的方法
类装载器
装载java编译器编译好的字节码*class和java api的字节码到方法区
java有两种类装载器
()启动类装载器系统唯一属于虚拟机的一部分用特定语言编写(与虚拟机体层语言相通)使用默认方式装载类主要用来装载核心类库
()用户自定义类装载器可有任意多个用java编写属于java应用程序的一部分能被编译成字节码并被虚拟机所装载
一个装载器装载一个类及其该类所调用的一切类使他们相互联系并形成一个命名空间(name space)每一个类装载器对应一个命名空间即java中名字空间的原理
类装载器成线形排列自底向上顶部为启动类装载器除启动类装载器外其他类装载器都由用户实例化用来装载不同的类当要装载一
个类时底部的装载器试图将该类交给父装载器装载而该父类又试图交给他的父类装载一直向上直到启动类装载器若父类装载器无法
装载则交给子类装载器装载子类装载能装载的部分将余下部分交给他的子类直到底部如
装载器abcdef启动
a>b>c>d>e>f>启动
当有一个类fun需要被装载时他会一直上溯到顶部即启动类装载器如果启动类装载器无法装载fun则交给f装载f装载能装载的部分将其
余部分交给e然后一直这样下去
如上所述运行过程中每个类装载器装载的类形成一个运行时包同一运行时包里的类可以互相访问但不能访问包外部的类
虚拟机的生命周期
每个java程序都有自己的虚拟机实例随着程序的产生和消亡而产生与消亡
java程序运行时的内存结构
程序空间分为方法区堆java栈本地方法栈
()方法区存放装载的类数据信息包括
基本信息
每个类的全限定名
每个类的直接超类的全限定名(可约束类型转换)
该类是类还是接口
该类型的访问修饰符
直接超接口的全限定名的有序列表
每个已装载类的详细信息
运行时常量池存放该类型所用的一切常量(直接常量和对其他类型字段方法的符号引用)它们以数组形式通过索引被访问是外部调用
与类联系及类型对象化的桥梁它是类文件(字节码)常量池的运行时表示(还有一种静态常量池在字节码文件中)
字段信息类中声明的每一个字段的信息(名类型修饰符)
方法信息类中声明的每一个方法的信息(名放回类型参数类型修饰符方法的字节码和异常表)
静态变量
到类classloader的引用即到该类的类装载器的引用
到类class的引用虚拟机为每一个被装载的类型创建一个class实例用来代表这个被装载的类
()堆存放所有生成的对象及对象的实例变量
()java栈以帧的形似存放本地方法的调用状态(包括方法调用的参数局部变量中间结果等)每调用一个方法就将对应该方法的方法帧压入
java栈成为当前方法帧当调用结束(返回)时就弹出该帧编译器将原代码编译成字节码(class)时就已经将各种类型的方法的局部变
量操作数栈大小确定并放在字节码中随着类一并装载入方法区当调用方法时通过访问方法区中的类的信息得到局部变量以及操作数
栈的大小
java栈帧(即方法帧)由局部变量区操作数栈帧数据区组成
局部变量区为一个以字为单位的数组每个数组元素对应一个局部变量的值调用方法时将方法的局部变量组成一个数组通过索引来访问若为非静态方法则加入一个隐含的引用参数this该参数指向调用这个方法的对象而静态方法则没有this参数因此对象无法调用静态
方法
操作数栈也是一个数组但却是通过栈操作来访问所谓操作数是那些被指令操作的数据当需要对参数操作时如a=b+c就将即将被操作的参数压栈如将b和c压栈然后由操作指令将他们弹出并执行操作此处由iadd指令将b和c弹出并相加然后压入操作数栈(一系列均由iadd执行)然后由i_storex指令将结果弹出存到索引x指向的局部变量区数组内(此处索引x指向局部变量a)
虚拟机将操作数栈作为工作区
帧数据区处理常量池解析异常处理等
()本地方法栈与调用的本地方法的语言相关如调用的是一个c语言方法则为一个c栈本地方法可以回调java方法
若有java方法调用本地方法虚拟机就运行这个本地方法在虚拟机看来运行这个本地方法就是执行这个java方法如果本地方法抛出异常虚拟机就认为是这个java方法抛出异常
()执行程序时通过对象的引用在方法区中查找装载的类若还没有装载则查找字节码(类名class)并将其装载入方法区
在执行过程中虚拟机会将对象的符号引用(即对象名)替换为直接的指针以提高访问速度
()因此大体可以表述为
方法区存储类包括接口的各种信息字节码装载到此处
java栈存储被调用的方法的各种信息只有调用该方法时才会将该方法帧压入java栈
堆存储对象的信息包括对象的实例变量但不包括对象的方法只有调用对象的方法时才将方法帧压入java栈中
java数据类型
数值类型
浮点类型float double
整数类型byteshortintlongchar(int和char可以互换)
引用类型类类型接口类型数组类型
java的引用类型
引用与指针
引用代表被引用的对象它只是引用对象的代表并不占用内存也不能修改如引用变量没有引用对象则该引用变量=null
指针存放对象的地址它是一个变量可以被修改和其他变量一样占用内存
方法区
所有线程共享方法区但为满足线程安全方法区中每一个类必须被设定为临界资源即同一时刻某一个类只能被一个线程访问
类标识
由于一个程序可以多次装载同一个类且该类可以存在于不同的名字空间中(即可由不同的装载器装载)因此必须将装载该类的装载器的标识加上才能唯一标识一个类
对象
对象实例变量存储在堆中对象符号引用则在常量池方法属性表等可能出现的地方通过对象的引用可以访问对象的实例数据和创建该对象
的类的数据对象的引用指向堆中的对象
实例结构有两种见书本页
当调用对象的方法时需要进行动态绑定即不能根据对象来确定需要调用的方法而是根据对象的类数据来确定需要调用的方法此时也需要通过对象的引用来访问类数据
动态绑定就是在运行时才绑定而不是在编译时绑定