深入JVM——常量池

[size=medium] 上面主要分析了方法区以及方法区中的静态区域,下面将主要分析下常量池。常量池主要涉及到常量池里的内容和常量池解析这两块,这篇文章主要分析下常量池概念,大致说下常量池解析,以加深对常量池的理解。
在方法区中,每个类型都对应一个常量池,常量池中存储了诸如[color=blue]文字字符串、final变量值、类名和方法名常量[/color]。JVM把常量池组织为入口列表的形式,可通过索引来访问常量池中的各个入口,每个常量池入口的第一个字节都是个标志,用这个标志来表示该入口中存储的常量类型,如[b]CONSTANT_Long[/b]表示里面存储的是long类型字面值,[b]CONSTANT_Class_info[/b]表示里面存的是某个Class的类型信息(存的可能是个普通的字符串,然后经过常量池解析,则变成指向某个类的引用)。
除了字面常量值以外,常量池还可以容纳其它几种符号引用:[color=blue]类和接口的全限定名、字段名称和描述符、方法名称和描述符[/color]。
类和接口的全限定名指的是当前类的全限定名。
字段名称指的是类或接口的实例变量或类变量,字段的描述符是一个指示字段的类型的字符串。如在一个类中有以下形式的声明:A a = null, 则a为字段名,A为字段描述符。
方法的描述符也是个字符串,该字符串指示了方法的返回值和参数的数量、顺序和类型。
在运行时,JVM从常量池中获得符号引用,然后在运行时解析成引用项的实际地址,最后通过常量池中的全限定名、方法和字段描述符,把当前类或接口中的代码与其它类或接口中的代码联系起来。
讲到常量池,就涉及到常量池解析,常量池解析是非常复杂的,它分多种情况处理。这里,就列举个简单的例子,大家看看,大概了解下常量池解析的大概过程。

测试例子程序:[/size]
 /**
* Dog的超类是个接口,而不是类
*/
public class Animal {

String id = "Animal"; //当类变量是static final

public void print() {
System.out.println("this is animal"+id);
}
}

/**
* 测试类
*/
public class Test {

public static void main(String[] args) {
Animal a = new Dog();
}

}


[size=medium]下面将描述下JVM是如何处理Test类中的main()方法的第一条指令:

要运行Test程序,JVM找到对应的Test.class文件,并读入到方法区中。通过保存在方法区中的字节码,JVM开始执行main方法,执行时,它会一直指向当前类(Test类)的常量池。 main的第一条指令告诉JVM要为常量池中的第一项类分配足够的内存,于是JVM使用Test常量池指针找到第一项,发现它是一个对Animal类的符号引用(也就是对字符串“Animal”的引用),于是JVM检查方法区,看Animal类是否被装载了。
如JVM发现还没装载过Animal类时,它开始查找并装载Animal.class文件。
最后,JVM将一个直接指向方法区Animal类数据的指针来代替常量池第一项(也就是那个字符串”Animal”),以后,则可以通过该指针来快速访问Animal类了,这个就称为常量池解析。[/size]

[size=medium]说了那么多,常量池解析在这里作的处理就是把常量池中的字符串"Animal"解析成一个对类Animal的引用。[/size]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值