详解JAVA 常量池

 更新时间:2020年07月14日 11:15:45   作者:团队buff工具人  
这篇文章主要介绍了JAVA 常量池的相关资料,文中讲解非常详细,示例代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下

前言

对常量池的理解之前,需要熟悉的是一些术语:

字面量

在计算机科学中,字面量(literal)是用于表达源代码中一个固定值的表示法(notation)。
几乎所有计算机编程语言都具有对基本值的字面量表示,诸如:整数、浮点数以及字符串;而有很多也对布尔类型和字符类型的值也支持字面量表示;
还有一些甚至对枚举类型的元素以及像数组、记录和对象等复合类型的值也支持字面量表示法。C语言关于复合字面量的介绍可参考: [1]  。

百度也给了一个例子:

这个object-c 的例子,容易理解。

#include <stdio.h>
int main(void)
{ 
 int a = 10; // 10为int类型字面量
 char a[] = {"Hello world!"} // Hello world 为字符串形式字面量
  .............
 // 以此类推,不再赘述
 return 0;
}

正文

JVM常量池主要分为Class文件常量池、运行时常量池,全局字符串常量池,以及基本类型包装类对象常量池。

我在网上找了一个例子:

private int value = 1;
public String s = "abc";
public final static int f = 0x101;
public static void main(String[] args)
{
}
public void setValue(int v){
	final int temp = 3;
	this.value = temp + v;
}
public int getValue(){
	return value;
}

编译后:

下面只截取了一部分,常量池:

public class test.program
 minor version: 0
 major version: 57
 flags: (0x0021) ACC_PUBLIC, ACC_SUPER
 this_class: #1       // test/program
 super_class: #3       // java/lang/Object
 interfaces: 0, fields: 3, methods: 4, attributes: 1
Constant pool:
 #1 = Class    #2    // test/program
 #2 = Utf8    test/program
 #3 = Class    #4    // java/lang/Object
 #4 = Utf8    java/lang/Object
 #5 = Utf8    value
 #6 = Utf8    I
 #7 = Utf8    s
 #8 = Utf8    Ljava/lang/String;
 #9 = Utf8    f
 #10 = Utf8    ConstantValue
 #11 = Integer   257
 #12 = Utf8    <init>
 #13 = Utf8    ()V
 #14 = Utf8    Code
 #15 = Methodref   #3.#16   // java/lang/Object."<init>":()V
 #16 = NameAndType  #12:#13  // "<init>":()V
 #17 = Fieldref   #1.#18   // test/program.value:I
 #18 = NameAndType  #5:#6   // value:I
 #19 = String    #20   // abc
 #20 = Utf8    abc
 #21 = Fieldref   #1.#22   // test/program.s:Ljava/lang/String;
 #22 = NameAndType  #7:#8   // s:Ljava/lang/String;
 #23 = Utf8    LineNumberTable
 #24 = Utf8    LocalVariableTable
 #25 = Utf8    this
 #26 = Utf8    Ltest/program;
 #27 = Utf8    main
 #28 = Utf8    ([Ljava/lang/String;)V
 #29 = Utf8    args
 #30 = Utf8    [Ljava/lang/String;
 #31 = Utf8    setValue
 #32 = Utf8    (I)V
 #33 = Utf8    v
 #34 = Utf8    temp
 #35 = Utf8    getValue
 #36 = Utf8    ()I
 #37 = Utf8    SourceFile
 #38 = Utf8    program.java

好的下面介绍class 常量池;

class 常量池

主要包括:字面量和符号引用

首先字面量不是全部的字面量,如果不明白什么是字面值请看上面;

字符字面值:

#7 = Utf8               s
#20 = Utf8               abc

用final修饰的成员变量

#9 = Utf8               f
#11 = Integer            257

大概包含的就是这两种。

符号引用

符号引用主要设涉及编译原理方面的概念,包括下面三类常量:

类和接口的全限定名,也就是java/lang/String;这样,将类名中原来的"."替换为"/"得到的,主要用于在运行时解析得到类的直接引用,像上面

#5 = Class              #33            // JavaBasicKnowledge/JavaBean
#33 = Utf8               JavaBasicKnowledge/JavaBean

字段的名称和描述符,字段也就是类或者接口中声明的变量,包括类级别变量和实例级的变量

#4 = Fieldref           #5.#32         // JavaBasicKnowledge/JavaBean.value:I
#5 = Class              #33            // JavaBasicKnowledge/JavaBean
#32 = NameAndType       #7:#8          // value:I

#7 = Utf8               value
#8 = Utf8               I

//这两个是局部变量,值保留字段名称
#23 = Utf8               v
#24 = Utf8               temp

可以看到,对于方法中的局部变量名,class文件的常量池仅仅保存字段名。

方法中的名称和描述符,也即参数类型+返回值

 #21 = Utf8               setValue
 #22 = Utf8               (I)V

 #25 = Utf8               getValue
 #26 = Utf8               ()I

其实并不需要怎么关注符号引用。

那么这些class 常量池有什么好处呢?

运行时常量池是方法区的一部分,所以也是全局贡献的,我们知道,jvm在执行某个类的时候,必须经过加载、链接(验证、准备、解析)、初始化,在第一步加载的时候需要完成:

通过一个类的全限定名来获取此类的二进制字节流

将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构

在内存中生成一个类对象,代表加载的这个类,这个对象是java.lang.Class,它作为方法区这个类的各种数据访问的入口。

类对象和普通对象是不同的,类对象是在类加载的时候完成的,是jvm创建的并且是单例的,作为这个类和外界交互的入口, 而普通的对象一般是在调用new之后创建。

上面的第二条,将class字节流代表的静态存储结构转化为方法区的运行时数据结构,其中就包含了class文件常量池进入运行时常量池的过程,这里需要强调一下不同的类共用一个运行时常量池,同时在进入运行时常量池的过程中,多个class文件中常量池相同的字符串,多个class文件中常量池中相同的字符串只会存在一份在运行时常量池,这也是一种优化。

运行时常量池的作用是存储java class文件常量池中的符号信息,运行时常量池中保存着一些class文件中描述的符号引用,同时在类的解析阶段还会将这些符号引用翻译出直接引用(直接指向实例对象的指针,内存地址),翻译出来的直接引用也是存储在运行时常量池中。

运行时常量池相对于class常量池一大特征就是具有动态性,java规范并不要求常量只能在运行时才产生,也就是说运行时常量池的内容并不全部来自class常量池,在运行时可以通过代码生成常量并将其放入运行时常量池中,这种特性被用的最多的就是String.intern()。

那么就看下String.intern() 来理解:运行时常量池。

首先看下:

string x="x" 和 String x=new String("x");

有什么区别?

可以肯定的是他们的值是一样的。

但是他们运行差别很大。string x="x" 会查找常量池,如果没有x的话,那么会存入常量池,如果有的话,那么会存在于常量池并进行引用。

而 String x=new String("x") 则只会生成在堆中,而不会和常量池产生联系。

注:

常量字符串和变量拼接时(如:String str3=baseStr + “01”;)会调用stringBuilder.append()在堆上创建新的对象。

那么String.intern() 是什么意思呢?这个是会去查找变量词中有没有,如果有的话那么会返回引用,如果没有的话,这个和版本有关。

题目

public static void main(String[] args) {
// write your code here
	Integer i01=59;
	int i02=59;
	Integer i03=Integer.valueOf(59);
	Integer i04= new Integer(59);
}

public static Integer valueOf(int i) {
	if (i >= IntegerCache.low && i <= IntegerCache.high)
		return IntegerCache.cache[i + (-IntegerCache.low)];
	return new Integer(i);
}

问题如下:

i01 是否和 i02 相等?

i03 是否和 i01 相等。

i04 是否和 i01相等。

总结

写的比较仓促,后续会完善好。

以上就是详解JAVA 常量池的详细内容,更多关于java 常量池的资料请关注脚本之家其它相关文章!

相关文章

  • JAVA中使用JSON进行数据传递示例

    JAVA中使用JSON进行数据传递示例

    本篇文章主要介绍了JAVA中使用JSON进行数据传递示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • java解析Excel的方法(xls、xlsx两种格式)

    java解析Excel的方法(xls、xlsx两种格式)

    这篇文章主要介绍了java解析Excel的方法(xls、xlsx两种格式),需要的朋友可以参考下
    2018-04-04
  • Hibernate5新特性介绍

    Hibernate5新特性介绍

    hibernate5中有了一些新的变动,下面脚本之家小编把Hibernate5新特性相关知识,分享到脚本之家平台,感兴趣的朋友参考下吧
    2017-09-09
  • Java正则表达式之split()方法实例详解

    Java正则表达式之split()方法实例详解

    这篇文章主要介绍了Java正则表达式之split()方法,结合实例形式较为详细的分析了split方法的功能、使用方法及相关注意事项,需要的朋友可以参考下
    2017-03-03
  • springboot2 生产部署注意事项及示例代码

    springboot2 生产部署注意事项及示例代码

    这篇文章主要介绍了springboot2 生产部署注意事项及示例代码,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-04-04
  • spring-spring容器中bean知识点总结

    spring-spring容器中bean知识点总结

    在本篇文章里小编给大家分享了关于spring-spring容器中bean知识点总结,有需要的朋友们可以学习下。
    2019-08-08
  • java自动根据文件内容的编码来读取避免乱码

    java自动根据文件内容的编码来读取避免乱码

    这篇文章主要介绍了java自动根据文件内容的编码来读取避免乱码,需要的朋友可以参考下
    2014-02-02
  • java常见的字符串操作和日期操作汇总

    java常见的字符串操作和日期操作汇总

    本文主要对java 常见的字符串操作和日期操作进行整理。具有一定的参考价值,需要的朋友一起来看下吧
    2016-12-12
  • Java基于Rest Assured自动化测试接口详解

    Java基于Rest Assured自动化测试接口详解

    Rest Assured 是一个基于 Java 的流行的用于测试 RESTful API 的库。这篇文章主要介绍了Java如何基于Rest Assured实现自动化测试接口,需要的可以参考一下
    2023-03-03
  • 解读Maven安装全过程

    解读Maven安装全过程

    下载并安装Maven时,需注意IDE的兼容版本,例如,IDEA2022及之前兼容至Maven3.8.1,而IDEA2020则至3.6.3,安装后,配置MAVEN_HOME环境变量并调整settings.xml以使用本地仓库和阿里云镜像,以优化构建和下载速度,最后,确保IDEA项目默认使用正确的Maven配置
    2024-11-11

最新评论