您的位置:首页 > 其它

深入JVM——常量池

2017-08-22 16:32 183 查看
上面主要分析了方法区以及方法区中的静态区域,下面将主要分析下常量池。常量池主要涉及到常量池里的内容和常量池解析这两块,这篇文章主要分析下常量池概念,大致说下常量池解析,以加深对常量池的理解。 

      在方法区中,每个类型都对应一个常量池,常量池中存储了诸如文字字符串、final变量值、类名和方法名常量。JVM把常量池组织为入口列表的形式,可通过索引来访问常量池中的各个入口,每个常量池入口的第一个字节都是个标志,用这个标志来表示该入口中存储的常量类型,如CONSTANT_Long表示里面存储的是long类型字面值,CONSTANT_Class_info表示里面存的是某个Class的类型信息(存的可能是个普通的字符串,然后经过常量池解析,则变成指向某个类的引用)。 

      除了字面常量值以外,常量池还可以容纳其它几种符号引用:类和接口的全限定名、字段名称和描述符、方法名称和描述符。 

      类和接口的全限定名指的是当前类的全限定名。 

      字段名称指的是类或接口的实例变量或类变量,字段的描述符是一个指示字段的类型的字符串。如在一个类中有以下形式的声明:A a = null, 则a为字段名,A为字段描述符。 

      方法的描述符也是个字符串,该字符串指示了方法的返回值和参数的数量、顺序和类型。 

      在运行时,JVM从常量池中获得符号引用,然后在运行时解析成引用项的实际地址,最后通过常量池中的全限定名、方法和字段描述符,把当前类或接口中的代码与其它类或接口中的代码联系起来。 

      讲到常量池,就涉及到常量池解析,常量池解析是非常复杂的,它分多种情况处理。这里,就列举个简单的例子,大家看看,大概了解下常量池解析的大概过程。 

      

      测试例子程序: 
     

Java代码  


 /** 

 * 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();  

    }  

      

}  

      下面将描述下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类了,这个就称为常量池解析。 

      说了那么多,常量池解析在这里作的处理就是把常量池中的字符串"Animal"解析成一个对类Animal的引用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: