-
常量
2013-06-14 22:36:051、在c中,定义常量可以使用const和#define 格式:const 类型名 常量名 = 值 格式:#define 常量名 值 2、const与类型名的顺序可以互换 3、#define只是负责简单的替换 例子如下: #include #define CLASS...1、在c中,定义常量可以使用const和#define
格式:const 类型名 常量名 = 值
格式:#define 常量名 值
2、const与类型名的顺序可以互换
3、#define只是负责简单的替换
例子如下:
#include <stdio.h> #define CLASS "zhangzetian" #define DATE 20130614 #define AA PI* #define BB 10+student_num int main(){ const double PI = 3.14; int const student_num = 40; printf("PI=%g,student_num=%d\n",PI,student_num); printf("CLASS=%s,DATE=%d\n",CLASS,DATE); printf("AA*BB=%g\n",AA BB);//特别要注意这一行输出的结果 return 0; }
结果如下: -
详解JVM常量池、Class常量池、运行时常量池、字符串常量池(心血总结)
2020-07-06 22:41:57写在前面:博主是一位普普通通的19届二本大学生,平时最大的爱好就是听听歌,逛逛B站。博主很喜欢的一句话花开堪折直须折,莫待无花空折枝:博主的理解是头一次为人,就应该做自己想做的...常量池与Class常量池 2.运.写在前面:博主是一位普普通通的19届双非软工在读生,平时最大的爱好就是听听歌,逛逛B站。博主很喜欢的一句话
花开堪折直须折,莫待无花空折枝
:博主的理解是头一次为人,就应该做自己想做的事,做自己不后悔的事,做自己以后不会留有遗憾的事,做自己觉得有意义的事,不浪费这大好的青春年华。博主写博客目的是记录所学到的知识并方便自己复习,在记录知识的同时获得部分浏览量,得到更多人的认可,满足小小的成就感,同时在写博客的途中结交更多志同道合的朋友,让自己在技术的路上并不孤单。>本篇博客由于比较深入的写进JVM底层,所以如果有错误希望可以指出咱们共同讨论痛苦对我们来说,究竟意味着什么?司马迁在《报任安书》中一语道破,文王拘而演《周易》,仲尼厄而作《春秋》,屈原放逐乃赋《离骚》,左丘失明厥有《国语》。
目录:
1.常量池与Class常量池
2.运行时常量池
运行时常量池的简介
方法区的Class文件信息,Class常量池和运行时常量池的三者关系
3.字符串常量池
字符串常量池的简介
采用字面值的方式创建字符串对象
采用new关键字新建一个字符串对象
字符串池的优缺点
4.字符串常量池和运行时常量池之间的藕断丝连
常量池和字符串常量池的版本变化
String.intern在JDK6和JDK7之后的区别(重难点)
字符串常量池里存放的是引用还是字面量1.常量池
常量池,也叫 Class 常量池(常量池==Class常量池)。Java文件被编译成 Class文件,
Class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项就是常量池
,常量池是当Class文件被Java虚拟机加载进来后存放在方法区 各种字面量 (Literal)和 符号引用 。在Class文件结构中,最头的4个字节用于 存储魔数 (Magic Number),用于确定一个文件是否能被JVM接受,再接着4个字节用于 存储版本号,前2个字节存储次版本号,后2个存储主版本号,再接着是用于存放常量的常量池常量池主要用于存放两大类常量:字面量和符号引用量,字面量相当于Java语言层面常量的概念,如文本字符串,声明为final的常量值等,符号引用则属于编译原理方面的概念。如下
2.运行时常量池
2.1运行时常量池的简介
运行时常量池是方法区的一部分。运行时常量池是当Class文件被加载到内存后,Java虚拟机会 将Class文件常量池里的内容转移到运行时常量池里(运行时常量池也是每个类都有一个)。运行时常量池相对于Class文件常量池的另外一个重要特征是具备
动态性
,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中2.2方法区的Class文件信息,Class常量池和运行时常量池的三者关系
字符串常量池
3.1字符串常量池的简介
字符串常量池又称为:字符串池,全局字符串池,英文也叫
String Pool
。 在工作中,String类是我们使用频率非常高的一种对象类型。JVM为了提升性能和减少内存开销,避免字符串的重复创建,其维护了一块特殊的内存空间,这就是我们今天要讨论的核心:字符串常量池。字符串常量池由String类私有的维护。我们理清几个概念:
在JDK7之前字符串常量池是在永久代里边的,但是在JDK7之后,把字符串常量池分进了堆里边。看下面两张图:
在堆中的字符串常量池: **堆里边的字符串常量池存放的是字符串的引用或者字符串(两者都有)**下面例子会有具体的讲解
符号引用表会在下面讲
我们知道,在Java中有两种创建字符串对象的方式:
- 采用字面值的方式赋值
- 采用new关键字新建一个字符串对象。这两种方式在性能和内存占用方面存在着差别。
3.2采用字面值的方式创建字符串对象
package Oneday; public class a { public static void main(String[] args) { String str1="aaa"; String str2="aaa"; System.out.println(str1==str2); } } 运行结果: true
采用字面值的方式创建一个字符串时,JVM首先会去字符串池中查找是否存在"aaa"这个对象,如果不存在,则在字符串池中创建"aaa"这个对象,然后将池中"aaa"这个对象的引用地址返回给字符串常量str,这样str会指向池中"aaa"这个字符串对象;如果存在,则不创建任何对象,直接将池中"aaa"这个对象的地址返回,赋给字符串常量。
对于上述的例子:这是因为,创建字符串对象str2时,字符串池中已经存在"aaa"这个对象,直接把对象"aaa"的引用地址返回给str2,这样str2指向了池中"aaa"这个对象,也就是说str1和str2指向了同一个对象,因此语句System.out.println(str1== str2)输出:true
3.3采用new关键字新建一个字符串对象
package Oneday; public class a { public static void main(String[] args) { String str1=new String("aaa"); String str2=new String("aaa"); System.out.println(str1==str2); } } 运行结果: false
采用new关键字新建一个字符串对象时,JVM首先在字符串常量池中查找有没有"aaa"这个字符串对象,如果有,则不在池中再去创建"aaa"这个对象了,直接在堆中创建一个"aaa"字符串对象,然后将堆中的这个"aaa"对象的地址返回赋给引用str1,这样,str1就指向了堆中创建的这个"aaa"字符串对象;如果没有,则首先在字符串常量池池中创建一个"aaa"字符串对象,然后再在堆中创建一个"aaa"字符串对象,然后将堆中这个"aaa"字符串对象的地址返回赋给str1引用,这样,str1指向了堆中创建的这个"aaa"字符串对象。
对于上述的例子:
因为,采用new关键字创建对象时,每次new出来的都是一个新的对象,也即是说引用str1和str2指向的是两个不同的对象,因此语句
System.out.println(str1 == str2)输出:false字符串池的实现有一个前提条件:String对象是不可变的。因为这样可以保证多个引用可以同时指向字符串池中的同一个对象。如果字符串是可变的,那么一个引用操作改变了对象的值,对其他引用会有影响,这样显然是不合理的。
3.4字符串池的优缺点
字符串池的优点就是避免了相同内容的字符串的创建,节省了内存,省去了创建相同字符串的时间,同时提升了性能;另一方面,字符串池的缺点就是牺牲了JVM在常量池中遍历对象所需要的时间,不过其时间成本相比而言比较低。
4字符串常量池和运行时常量池之间的藕断丝连
博主为啥要把他俩放在一起讲呢,主要是随着JDK的改朝换代,字符串常量池有很大的变动,和运行时常量池有关。而且网上众说纷纭,我真的在看的时候ctm了,所以博主花很长时间把这一块讲明白,如果有错误或者异议可以通知博主。博主一定会在第一时间参与讨论
4.1常量池和字符串常量池的版本变化
- 在JDK1.7之前运行时常量池逻辑包含字符串常量池存放在方法区, 此时hotspot虚拟机对方法区的实现为永久代
- 在JDK1.7 字符串常量池被从方法区拿到了堆中, 这里没有提到运行时常量池,也就是说 字符串常量池被单独拿到堆,运行时常量池剩下的东西还在方法区, 也就是hotspot中的永久代
- 在JDK1.8 hotspot移除了永久代用元空间(Metaspace)取而代之, 这时候字符串常量池还在堆, 运行时常量池还在方法区, 只不过方法区的实现从永久代变成了元空间(Metaspace)
4.2String.intern在JDK6和JDK7之后的区别(重点)
JDK6和JDK7中该方法的功能是一致的,不同的是常量池位置的改变(JDK7将常量池放在了堆空间中),下面会具体说明。intern的方法返回字符串对象的规范表示形式。其中它做的事情是:首先去判断该字符串是否在常量池中存在,如果存在返回常量池中的字符串,如果在字符串常量池中不存在,先在字符串常量池中添加该字符串,然后返回引用地址
例子1:
String s1 = new String("1"); s1.intern(); String s2 = "1"; System.out.println(s1 == s2); 运行结果: JDK6运行结果:false JDK7运行结果:false
我们首先看一张图:
上边例子中s1是new出来对象存放的位置的引用,s2是存放在字符串常量池的字符串的引用,所以两者不同
例子2:
String s1 = new String("1"); System.out.println(s1.intern() == s1); 运行结果: JDK6运行结果:false JDK7运行结果:false
上边例子中s1是new出来对象存放的位置的引用,s1.intern()返回的是字符串常量池里字符串的引用
例子3:
String s1 = new String("1") + new String("1"); s1.intern(); String s2 = "11"; System.out.println(s1 == s2); 运行结果: JDK6运行结果:false JDK7运行结果:true
JDK6中,s1.intern()运行时,首先去常量池查找,发现没有该常量,则在常量池中开辟空间存储"11",返回常量池中的值(注意这里也没有使用该返回值),第三行中,s2直接指向常量池里边的字符串,所以s1和s2不相等。有可能会有小伙伴问为啥s1.intern()发现没有该常量呢,那是因为:
String s1 = new String(“1”) + new String(“1”);这行代码实际操作是,创建了一个StringBuilder对象,然后一路append,最后toString,而toString其实是又重新new了一个String对象,然后把对象给s1,此时并没有在字符串常量池中添加常量
JDK7中,由于字符串常量池在堆空间中,所以在s1.intern()运行时,发现字符串 常量池没有常量,则添加堆中“11”对象的引用到字符串常量池,这个引用返回堆空间“11”地址(注意这里也没有使用该返回值),这时s2通过查找字符串常量池中的常量,查到的是s1.intern()存在字符串常量池里的“11”对象的引用,既然都是指向堆上的“11”对象,所以s1和s2相等。
例子4:
String s1 = new String("1") + new String("1"); System.out.println(s1.intern() == s1);
JDK6中,常量池在永久代中,s1.intern()去常量池中查找"11",发现没有该常量,则在常量池中开辟空间存储"11",返回常量池中的值,s1指向堆空间地址,所以二者不相等。
JDK7中,常量池在堆空间,s1.intern()去常量池中查找"11",发现没有该常量,则在字符串常量池中开辟空间,指向堆空间地址,则返回字符串常量池指向的堆空间地址,s1也是堆空间地址,所以二者相等。
另外美团的团队写了一篇关于intern()的博客,我觉得很好可以参考一下
深入解析String#intern4.3字符串常量池里存放的是引用还是字面量
我在例子3中讲了在JDK7中字符串常量池在堆上,仔细看看例3啥时候会放引用
那么啥时候会放字面量在字符串常量池呢,那就是在我们new一个String对象的时候如果字符串常量池里边有字面量那么就不会放,如果字符串常量池没有就会放字面量。看一个例子:
package Oneday; import java.util.HashSet; import java.util.Set; public class a { public static void main(String[] args) { String str1= new String("123"); String str2=new String("123"); System.out.println(str1==str2); System.out.println(str1.intern()==str2.intern()); } }
运行结果:
首先String str1= new String("123");
会在堆中创建一个对象,返回这个对象的引用给str1,同时它还会在字符串常量池中检查有没有有没有123这个对象,如果没有就==再创建一个对象(也就是123这个字面量)==在字符串常量池中注意这里是创建了两个对象
但是当我们字符串常量池里边有123这个对象,那么就不用继续创建了
上面例子的false那是因为堆中的123对象不是同一个对象,但是第二个str1.intern和s2.intern指的都是字符串常量池里的123对象所以是true
-
常量指针和指针常量和常量指针常量
2018-12-23 21:18:23常量指针和指针常量和常量指针常量 **常量指针:**指向常量的指针。 示例一: int n = 10; const int *p = &amp;n; 此时不能通过指针修改数据对象的值,但可以改变指针的指向。比如此时指针p不能改变n的值...常量指针和指针常量和常量指针常量
常量指针:指向常量的指针。
示例一:
int n = 10; const int *p = &n;
此时不能通过指针修改数据对象的值,但可以改变指针的指向。比如此时指针p不能改变n的值,但是可以指向另一个变量,把上面的代码做修改:
int n = 10, m = 30; const int *p = &n;//常量指针p初始化指向n *p = 20;// 这一步错误,这是一个常量指针,不能更改目标数据对象的值 p = &m;//这一步正确,可以修改指向
示例二:
void PrintObj(const int *p);
比如我们要定义一个函数,功能是打印某个对象的值,我们此时只希望函数有打印功能,不希望传进来的指针可以被修改,我们就把它变成常量指针,这样就只能打印,不能修改.
指针常量:指针指向的位置不可变化。
要注意一下,指针常量和其他常量一样,必须在定义时初始化。
此时不可以把指针指向其他地方,但是可以改变指针所指的目标数据对象的值。
示例一:
int n = 10, m = 30; int *const p = &n;//定义一个指针常量指向n *p = 40;//合法,可以改变指针所指的目标数据对象的值 p = &m;//不合法,不能修改指针指向。
常量指针常量:指向常量的指针常量(指针的双重只读属性)
他的性质是**:指针值不可改变,指向的目标数据对象也不可改变。**
int n = 10, m = 30; const int *const p = &n; *p = 40;//错误 p = &m;//错误
使用场合,作为函数的参数.
-
常量池,常量池,常量池,常量池
2016-11-28 06:02:51常量池怎么理解,常量池怎么理解,常量池怎么理解!常量池怎么理解,常量池怎么理解,常量池怎么理解, -
Java常量
2019-09-29 00:09:34常量值定义:常量和常量值是不同的概念,常量值又称为字面常量,它是通过数据直接表示的。 关系:常量值是常量的具体和直观的表现形式,常量是形式化的表现。通常在程序中既可以直接使用常量值,也可以使用常量。 ...定义
- 常量定义:在程序执行的过程中,其值不可以发生改变的量。常量不同于常量值,它可以在程序中用符号来代替常量值使用,因此在使用前必须先定义。
- 常量值定义:常量和常量值是不同的概念,常量值又称为字面常量,它是通过数据直接表示的。
- 关系:常量值是常量的具体和直观的表现形式,常量是形式化的表现。通常在程序中既可以直接使用常量值,也可以使用常量。
分类
- 字符串常量 用双引号括起来的内容(“HelloWorld”)
- 整数常量 所有整数(12,-23)
- 小数常量 所有小数(12.34)
- 字符常量 用单引号括起来的内容(‘a’,’A’,’0’)
- 布尔常量 较为特有,只有true和false
- 空常量 null(数组部分讲解)
举例
- Java 语言使用 final 关键字来定义一个常量
final int COUNT=10;
final float HEIGHT=10.2F;
注意事项
- 在定义常量时就需要对该常量进行初始化。
- final 关键字不仅可以用来修饰基本数据类型的常量,还可以用来修饰对象的引用或者方法。
- 为了与变量区别,常量取名一般都用大写字符。
-
指针常量和常量指针
2018-08-22 10:53:041、指针常量——指针类型的常量(int *const p) 本质上一个常量,指针用来说明常量的类型,表示该常量是一个指针类型的常量。在指针常量中,指针自身的值是一个常量,不可改变,始终指向同一个地址。在定义的同时... -
常量与符号常量
2019-04-16 20:53:05通过“数学中的变量与常量”章节的介绍,我们知道了常量的定义,就是其数据不可以修改的量。例如100这个数值,它的数值就是100,不可以改变,所以,称为常量,可以称为:常量100。 那么,在C语言中定义的数据包括有... -
指针常量 常量指针
2017-08-25 11:33:31指针常量(指向常量的指针): const int *pa; int const *pa; 两者等价。因为指向常量的指针有时候会指向常量,所以它具有这个性质:“不能靠解引用改变它指向的对象的值”,以此保护它所指向的常量的常量性。 ... -
常量池,常量池,常量池,常量池,
2016-11-28 05:28:46学习java需要深刻理解常量池吗?学习java需要深刻理解常量池吗?学习java需要深刻理解常量池吗? -
指针常量 常量指针 常量指针常量
2013-05-07 20:36:43其实对于指针常量、常量指针、常量指针常量这三个专用名词应经基础很久了,不过总是过一段时间就忘了或者把这三个给记混淆了。今天又遇到了这个问题,于是就想好好研究下这三个名词,以便于加深印象。 先看下: ... -
整型常量与实型常量、符号常量和字符常量的区别
2018-10-31 08:41:54符号常量指的是被定义的常量,在C语言中用一个标识符来替代一个常量,就说这个标识符是符号常量,如(#define 标识符 常量这个预处理命令“#define PI 3.14&amp;amp;amp;amp;amp;amp;quot;中,PI就是符号... -
Golang 常量
2020-08-03 19:24:12相对于变量, 常量是恒定不变的值, 经常用于定义程序运行期间不会改变的那些值. 常量的定义使用 常量的声明与变量的声明很相似, 只是把 var 换成了 const, 常量在定义的时候必须赋值. 在程序开发中, 我们用常量存储... -
指针常量、常量指针与指向常量的指针常量小结(C/C++)
2018-10-22 15:06:04一 指针常量: int a; int *const pcb = &a; //const放在指针声明操作符的右侧 只要const位于指针声明操作符右侧,就表明声明的对象是一个常量,且它的内容是一个指针,也就是一个地址。上面的声明可以... -
整型常量、实型常量、字符常量、符号常量、枚举常量的区别
2019-07-29 19:35:21整型常量默认数据类型是int,当数值超过int时,类型会变成long,超过long会报warning; 符号常量默认数据类型是int,当数值超过int时,类型会变成long,超过long会报warning; 枚举常量默认数据类型是int,当数值... -
字符串常量池、class常量池和运行时常量池
2017-06-12 20:09:36在java的内存分配中,经常听到很多关于常量池的描述,我开始看的时候也是看的很模糊,网上五花八门的说法简直太多了,最后查阅各种资料,终于算是差不多理清了,很多网上说法都有问题,笔者尝试着... -
常量指针和指针常量
2020-07-05 10:54:31// pi是一个常量,不能改变它的值 const double pi = 3.14; //cptr指向pi,注意这里的const不能丢,因为普通指针不能指向常量对象,即,不能用非const变量初始化指向常量的指针. const double *cptr = π *cptr =... -
Java中的常量池(字符串常量池、class常量池和运行时常量池)
2017-08-24 17:58:00这几天在看Java虚拟机方面的知识时,看到了有几种不同常量池的说法,然后我就去CSDN、博客园等上找资料,里面说的内容真是百花齐放,各自争艳,因此,我好好整理了一下,将我自认为对的理解写下来与大家共同探讨: ... -
C++指针常量与常量指针
2020-07-08 11:21:35首先,常量与变量的概念很容易区分,在c++中,常量常用const修饰,即不可变的量。 指针常量:本质是一个常量,并且使用指针来修饰它,那么说明这个常量的值应该是一个指针,其格式应为:int * const p。 常量指针:... -
指向常量的指针和常量指针;常量指针和指针常量;指向常量的常指针;
2020-06-22 00:46:34今天看书看到常量指针发现和我以前看到的常量指针怎么是反的,本来以为书上是错的,然后深究一下。其实都没错,是翻译的方式不同而已,其实指的一个意思。可以划分一下: 指向常量的指针和常量指针为一组说法,常量... -
C语言——常量指针、指针常量以及指向常量的指针常量三者区别详解
2017-12-20 18:10:28常量指针和指针常量的区别 常量指针、指针常量以及指向常量的指针常量概念简要描述 -
区别:指针常量、指针变量、常量指针和常量指针常量
2017-10-11 14:37:323.常量指针:指向常量的指针,所以不能修改指向的实体的值,但可以修改指针的指向(即可以指向别的常量,必须是常量); 4.常量指针常量:指向常量,指针不能改变指向的实体的值,指针值(即指针的指向)也不能改变... -
常量指针和指针常量的区别
2018-05-24 22:57:09在面试中我们经常会被面试官问到什么是常量指针,什么又是指针常量。可能第一次被问到都会有些懵逼(大神略过)。我今天就来讲一讲这二者的区别。 下面开始正题。。。。 指针常量 指针常量:顾名思义它就是一个... -
名字常量_字面值常量_常量
2017-01-23 15:23:12#define MAX_LEN 50这句话中的MAX_LEN叫做名字常量。50叫做整行字面常量。 "I love you!"----字符串常量。比较特殊的是,它的内容不仅是常量,而且隐含着首字符的地址。 ‘A’---字符字面常量。 char c = 'A'; //... -
C++常量(C++数值常量、字符串常量、符号常量)
2017-08-03 12:13:21数值常量 数值常量就是通常所说的常数。在C++中,数值常量是区分类型的,从字面形式即可识别其类型。 整型常量(整数)的类型 在上一节中已知道:整型数据可分为int, short int,long int以及unsigned int, ... -
Vue定义常量、常量使用
2020-03-20 15:17:58项目开发中常量的定义和使用都是广泛的 就比如说正则表达式等等 直接上码 有限创建存放常量的文件目录 (名字自拟) partten.js 文件用于存放需要的常量 使用export const 进行声明(此处以正则位例) export const... -
Java常量(字面值常量和自定义常量)
2019-10-21 15:15:42字面值常量 之所以称之为字面值是因为只能用它的值来称呼它,称之为常量是因为它的值不能修改。 对于字面值常量我们分为以下五种: 类别 示例 说明 整型 10、12 主要是有进制的区别,默认... -
【JVM】探究Java常量本质及三种常量池
2019-07-22 21:35:10之前从他人的博文,还有一些书籍中了解到 常量是放在常量池 中,细节的内容无从得知,总觉得面前的东西是一个几乎完全的黑盒,总是觉得不舒服,于是就翻阅《深入理解Java虚拟机》,这本书中对常量的介绍更多地偏重于...
-
股票投资了解
-
python课件.rar
-
303. 区域和检索 - 数组不可变(前缀和)
-
第 229 场周赛记录(460 / 3483 )
-
2019年-华启学院中级通信工程师综合能力真题及答案(完整版).pdf
-
基于SSM实现的房屋租赁系统【附源码】(毕设)
-
MPC第1期.rar
-
FTP 文件传输服务
-
【Flutter】StatefulWidget 组件.zip
-
MHA 高可用 MySQL 架构与 Altas 读写分离
-
_this2.$xxxis not a function
-
一天学完MySQL数据库
-
《ChinaTeXMathFAQ_V1.1》.pdf
-
redis-6.0.6-windows.zip
-
Java自学第九天 练习
-
C++代码规范和Doxygen根据注释自动生成手册
-
前缀和相关:区域和检索 - 数组不可变 ...
-
PS2手柄源码.zip
-
C++ STL(十四):常用排序算法(sort、random_shuffle、merge、reverse)
-
MySQL 管理利器 mysql-utilities