纠正以前对java的错误理解
1、以前以为java和c一样是静态语言编译过程一样,但是实际上java是先被编译器编译为class文件,也就是可以被JVM识别的文件,然后再由JVM解释为机器可识别的二进制文件运行。
而且整个过程是程序运行时进行的。所以java既有动态特性,又有静态特性。
灵活性体现:
当用户运行程序时,可以从网络或者其他地方加载class文件,实现动态加载应用程序。
类的加载过程:
连接过程并不像C那样将.o文件连接在一起生成可执行文件,还进行了验证、准备、解析等。
加载过程
(1) 通过一个类的全限定名字来获取定义此类的二进制字节流
(2) 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
(3) 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种访问入口
由此可见,传入的字节流数据可以用多种方式实现。
例如:
1、从jar ERA WAR等压缩文件中传入
2、从网络获取,也就是Applet
3、运行时计算生成,也就是动态代理技术,在java.lang.reflect.Proxy中
4、由其他文件生成,典型场景是JSP,由JSP文件生成对应的Class
5、从数据库获取,场景较少,如中间件服务器SAP netweaver
验证阶段
1、文件格式验证
是否是以魔数开头0xCAFEBABE
…
2、元数据验证
检查类是否满足要求
3、字节码验证
语义、语法分析,这是最复杂的一步
4、符号引用验证
准备阶段
为变量分配内存并设置类变量初始值
解析阶段
将常量池内的符号引用替换为直接引用的过程
初始化阶段
执行类构造器的()方法的过程
类加载器
通过一个类的全限定名来获取描述此类的二进制流,一个类加载器有自己独立的类命名空间,所以如果同一个class的类,放在不同的类加载器加载是不想等的。
栈帧结构
局部变量
局部变量表容量以slot为最小单位,slot一般可存32bit长度
java中的局部变量作用域可以用{}来分割,局部变量的slot是可以复用的,PC计数器超过了局部变量的作用域,那么此变量申请的slot就可以被复用,换而言之就是可以回收。
public class main {
public static void main(final String[] args){
{
byte[] placehold = new byte[64*1024*1024];
}
int a = 0; //进行复用,解除placehold与slot的关联
System.gc();
}
}
因此,局部变量推荐进行手动清0操作以免出现问题
操作数栈
动态连接
运行期间将变量引用转换为直接引用
方法返回地址
return
函数重载
一个类中多个同名函数,调用时会根据传参的属性来选择调用函数