好好说说Java中的常量池之Class常量池

转载自   好好说说Java中的常量池之Class常量池

在Java中,常量池的概念想必很多人都听说过。这也是面试中比较常考的题目之一。在Java有关的面试题中,一般习惯通过String的有关问题来考察面试者对于常量池的知识的理解,几道简单的String面试题难倒了无数的开发者。所以说,常量池是Java体系中一个非常重要的概念。

谈到常量池,在Java体系中,共用三种常量池。分别是字符串常量池、Class常量池和运行时常量池。

本文是《好好说说Java中的常量池》系列的第一篇,先来介绍一下到底什么是Class常量池。

 

 

什么是Class文件

在Java代码的编译与反编译那些事儿中我们介绍过Java的编译和反编译的概念。我们知道,计算机只认识0和1,所以程序员写的代码都需要经过编译成0和1构成的二进制格式才能够让计算机运行。

我们在深入分析Java的编译原理中提到过,为了让Java语言具有良好的跨平台能力,Java独具匠心的提供了一种可以在所有平台上都能使用的一种中间代码——字节码(ByteCode)

有了字节码,无论是哪种平台(如Windows、Linux等),只要安装了虚拟机,都可以直接运行字节码

同样,有了字节码,也解除了Java虚拟机和Java语言之间的耦合。这话可能很多人不理解,Java虚拟机不就是运行Java语言的么?这种解耦指的是什么?

其实,目前Java虚拟机已经可以支持很多除Java语言以外的语言了,如Groovy、JRuby、Jython、Scala等。之所以可以支持,就是因为这些语言也可以被编译成字节码。而虚拟机并不关心字节码是有哪种语言编译而来的。

Java语言中负责编译出字节码的编译器是一个命令是javac

javac是收录于JDK中的Java语言编译器。该工具可以将后缀名为.java的源文件编译为后缀名为.class的可以运行于Java虚拟机的字节码。

如,我们有以下简单的HelloWorld.java代码:

public class HelloWorld {public static void main(String[] args) {String s = "Hollis";}
}

通过javac命令生成class文件:

javac HelloWorld.java

生成HelloWorld.class文件:

 

如何使用16进制打开class文件:使用 vim test.class ,然后在交互模式下,输入:%!xxd即可。

可以看到,上面的文件就是Class文件,Class文件中包含了Java虚拟机指令集和符号表以及若干其他辅助信息。

要想能够读懂上面的字节码,需要了解Class类文件的结构,由于这不是本文的重点,这里就不展开说明了。

读者可以看到,HelloWorld.class文件中的前八个字母是cafe babe,这就是Class文件的魔数(Java中的”魔数”)

我们需要知道的是,在Class文件的4个字节的魔数后面的分别是4个字节的Class文件的版本号(第5、6个字节是次版本号,第7、8个字节是主版本号,我生成的Class文件的版本号是52,这时Java 8对应的版本。也就是说,这个版本的字节码,在JDK 1.8以下的版本中无法运行)在版本号后面的,就是Class常量池入口了。

 

 

Class常量池

Class常量池可以理解为是Class文件中的资源仓库。 Class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池(constant pool table),用于存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References)。

由于不同的Class文件中包含的常量的个数是不固定的,所以在Class文件的常量池入口处会设置两个字节的常量池容量计数器,记录了常量池中常量的个数。

当然,还有一种比较简单的查看Class文件中常量池的方法,那就是通过javap命令。对于以上的HelloWorld.class,可以通过

javap -v  HelloWorld.class

查看常量池内容如下:

从上图中可以看到,反编译后的class文件常量池中共有16个常量。而Class文件中常量计数器的数值是0011,将该16进制数字转换成10进制的结果是17。

原因是:与Java的语言习惯不同,常量池计数器是从1开始而不是从0开始的,常量池的个数是 十进制的17,这就代表了其中有16个常量,索引值范围为1-16。

 

常量池中有什么

介绍完了什么是Class常量池以及如何查看常量池,那么接下来我们就要深入分析一下,Class常量池中都有哪些内容。

常量池中主要存放两大类常量:字面量(literal)和符号引用(symbolic references)。

 

 

字面量

前面说过,运行时常量池中主要保存的是字面量和符号引用,那么到底什么字面量?

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

以上是关于计算机科学中关于字面量的解释,并不是很容易理解。说简单点,字面量就是指由字母、数字等构成的字符串或者数值。

字面量只可以右值出现,所谓右值是指等号右边的值,如:int a=123这里的a为左值,123为右值。在这个例子中123就是字面量。

int a = 123;
String s = "hollis";

上面的代码示例中,123和hollis都是字面量。

本文开头的HelloWorld代码中,Hollis就是一个字面量。

 

 

符号引用

常量池中,除了字面量以外,还有符号引用,那么到底什么是符号引用呢。

符号引用是编译原理中的概念,是相对于直接引用来说的。主要包括了以下三类常量:

  • 类和接口的全限定名 

  • 字段的名称和描述符 

  • 方法的名称和描述符

这也就可以印证前面的常量池中还包含一些com/hollis/HelloWorldmain([Ljava/lang/String;)V等常量的原因了。

 

Class常量池有什么用

前面介绍了这么多,关于Class常量池是什么,怎么查看Class常量池以及Class常量池中保存了哪些东西。有一个关键的问题没有讲,那就是Class常量池到底有什么用。

首先,可以明确的是,Class常量池是Class文件中的资源仓库,其中保存了各种常量。而这些常量都是开发者定义出来,需要在程序的运行期使用的。

在《深入理解Java虚拟》中有这样的表述:

Java代码在进行Javac编译的时候,并不像C和C++那样有“连接”这一步骤,而是在虚拟机加载Class文件的时候进行动态连接。也就是说,在Class文件中不会保存各个方法、字段的最终内存布局信息,因此这些字段、方法的符号引用不经过运行期转换的话无法得到真正的内存入口地址,也就无法直接被虚拟机使用。当虚拟机运行时,需要从常量池获得对应的符号引用,再在类创建时或运行时解析、翻译到具体的内存地址之中。关于类的创建和动态连接的内容,在虚拟机类加载过程时再进行详细讲解。

这段话,看起来很绕,不是很容易理解。其实他的意思就是: Class是用来保存常量的一个媒介场所,并且是一个中间场所。在JVM真的运行时,需要把常量池中的常量加载到内存中。

至于到底哪个阶段会做这件事情,以及Class常量池中的常量会以何种方式被加载到具体什么地方,会在本系列文章的后续内容中继续阐述。欢迎关注我的博客(https://www.hollischuang.com) 和公众号(Hollis),即可第一时间获得最新内容。

另外,关于常量池中常量的存储形式,以及数据类型的表示方法本文中并未涉及,并不是说这部分知识点不重要,只是Class字节码的分析本就枯燥,作者不想在一篇文章中给读者灌输太多的理论上的内容。感兴趣的读者可以自行Google学习,如果真的有必要,我也可以单独写一篇文章再深入介绍。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/322967.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spring cloud+.net core搭建微服务架构:Api授权认证(六)

前言 这篇文章拖太久了,因为最近实在太忙了,加上这篇文章也非常长,所以花了不少时间,给大家说句抱歉。好,进入正题。目前的项目基本都是前后端分离了,前端分Web,Ios,Android。。。,后端也基本是…

如何用spring boot写一个注册页面

环境准备: java集成开发环境:IDEA 数据库:Mysql Maven 最好在安装有个navicat(数据库可视化界面) 安装好上述几个软件后 总结下:五步 1、创建新的工程 2、创建建applicatiom.yml 3、创建entity层 4、创建r…

IDEA创建包不是树形

创建包的时候和别人的不一样,不是树形结构 可以点击图中的齿轮改变选项 把两个对勾取消掉就可以了 现在就是树形结构了

.NET Core跨平台的奥秘[下篇]:全新的布局

从本质上讲,按照CLI规范设计的.NET从其出生的那一刻就具有跨平台的基因,这与Java别无二致。由于采用了统一的中间语言,微软只需要针对不同的平台设计不同的虚拟机(运行时)就能弥合不同操作系统与处理器架构之间的差异&…

漫画:什么是拜占庭将军问题

转载自 漫画:什么是拜占庭将军问题 什么是拜占庭将军问题? 在很久很久以前,拜占庭是东罗马帝国的首都。那个时候罗马帝国国土辽阔,为了防御目的,因此每个军队都分隔很远,将军与将军之间只能靠信使传递消息…

SQL Server 审计

审计(Audit)用于追踪和记录SQL Server实例或数据库中发生的事件,审计主要包括审计对象(Audit)和审计规范(Audit Specification),创建审计首先需要创建一个SQL Server 实例级的审计对…

ASP.NET Core中的OWASP Top 10 十大风险-失效的访问控制与Session管理

本博文翻译自: https://dotnetcoretutorials.com/2017/10/16/owasp-top-10-asp-net-core-broken-authentication-session-management/ 在我们之前关于OWASP Top 10的文章中,我们讨论了SQL注入。SQL注入有一个非常明确的解释和例子,但这次我们…

Docker部署运行微服务

1、环境准备: 主机: X-shell X-ftp jar包 这里只说下jar包,另外两个到官网下载即可 Idea打包jar包流程 先按这四步走 先点击左下的框框,再点击maven,出现右边的窗口,点击clean,再点击package&…

.net ef core 领域设计代码转换(上篇)

一、前言 .net core 2.0正式版已经发布几个月了,经过研究,决定把项目转移过来,新手的话可以先看一些官方介绍 传送门:https://docs.microsoft.com/zh-cn/dotnet/core/ 由于在领域设计模型上遇到了一些坑,故给大家分享出…

Debug ASP.NET Core 2.0源代码

首先你的VS必须为VS 2017 15.3或以上版本。 打开你的Startup类,在ConfigureServices方法上设置个断点,按F5 Debug应用。 在Call Stack(调用堆栈)窗口,我们只能看到自己的代码。打开VS tools(工具&#xff…

我心中的ASP.NET Core 新核心对象WebHost(一)

以本系列文章向Fish 前辈的那篇我心中的ASP.NET 核心对象致敬。(虽然不知道前辈现在在干什么)。一晃就6年过去了,那首 郝云 的《回到那一天》怎么唱来着? 时光一晃,你就三十了。 而我们都变成了老了的程序员 ASP.NET …

Scaffolding Template on Asp.Net Core Razor Page

Scaffolding Template Intro 我们知道在Asp.Net MVC中,如果你使用的EF的DBContext的话,你可以在vs中通过右键解决方案-添加控制器-添加包含视图的控制器,然后vs会根据你选择的Model自动生成相应的CURD的控制器和View,非常便利&…

Hadoop生态hive(一)介绍

一、Hive是什么 起源自facebook由Jeff Hammerbacher领导的团队,构建在Hadoop上的数据仓库框架。设计目的是让SQL技能良好,但Java技能较弱的分析师可以查询海量数据。2008年facebook把hive项目贡献给Apache。 由facebook开源,最初用于解决海量…

使用混合云的SQL Server

近期发布的Microsoft SQL Server 2017,表明Microsoft公司正寻求不断降低其所交付的工具对平台的绑定。在SQL Server 2017中,这一趋势可以从“混合云”(Hybrid Cloud)术语和多平台本质这两个方面得以证实。下面让我们分别一窥这两个…

.NET Core多平台项目模板eShopOnContainers编译手记

之前写了一个功能性的文件上传asp.net core的小程序,加上点七七八八的东西,勉强能够应付了,打算学习一下微软的官方.NET CORE微服务示例https://github.com/dotnet-architecture/eShopOnContainers。这个例子很全面地展现了微服务、docker以及…

如何改变Idea的背景

进入Idea 按下ctrlshifta 点击set background 选择自己准备好的图片地址,就可以更改背景了 更改后效果 关于接口的插件 GsonFormat插件 安装还是和别的插件一样,在plugin里搜索GsonFormat,下载并重启 然后在model里的类 按下alts 出现 将…

TFS在项目中Devops落地进程(上)

作为一名开发,经过近2年折腾,基于TFS的Devops主线工程大体落地完毕。 在此大体回忆下中间的各种历程。 开始之前简单说下什么是TFS(Team Foundation Server)。 TFS是微软推出的一款ALM(Application Lifecycle Management)管理工具。 透过TFS你将能获取到从代码版本管…

Hadoop生态hive(三)Hive QL介绍

一、表 创建表 CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name CREATE TABLE 创建一个指定名字的表。Hive 创建内部表时,会将数据移动到数据仓库指向的路径; EXTERNAL 关键字可以让用户创建一个外部表,在建表的同时指定一个指向实…

抖音上非常火的旋转图快速部署

本教程不需要你有服务器! 本教程不需要你有服务器! 本教程不需要你有服务器! 点击我看旋转图 总共两步 1、注册一个码云账号 2、新建一个仓库,上传文件即可 1、注册账号的话,直接浏览器搜索码云,手机号…

Microsoft的现代数据管理

PASS 2017峰会是面向SQL Server及Microsoft相关数据技术用户的大会。在大会的第一天,Microsoft的Rohan Kumar先生到场做了开幕式的主题演讲,并借此机会展示了Microsoft在SQL Server和Azure数据库方面的最新进展。 Kumar的演讲涉及数据、人工智能和云这三…