常量与变量(数学层面)
常量:就是有固定值的量
变量:没有固定值的量,只是用字母表示
-----------------------------------------------------------------------------------------------------------------------------------------------------
java常量分2种,一般常量与不可变常量
一般常量
一个值,就是这个值本身,如8种基本类型、文本字符串等。
不可变常量,(也就是不可变的变量)
就是被我们都知道的关键字final修饰的变量。
-----------------------------------------------------------------------------------------------------------------------------------------------------
常量池分3种,字符串常量池、class常量池与运行时常量池
字符串常量池(String Constant Pool)
简介:
字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串,极大程度地影响程序的性能
JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化
专门为字符串开辟一个字符串常量池,类似于缓存区
创建字符串常量时,首先检查字符串常量池是否存在该字符串
存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中
时机:编译或运行
位置:
jdk1.6 方法区
jdk1.7 ?
特点:
字符串常量池中的字符串只能存一份
String s1 = "hello,world!";
String s2 = "hello,world!";
s1创建后,常量池中已存在 “hello,world!”,那么s2不会在常量池中申请新的空间,而是直接把已存在的字符串内存地址返回给s2。
备注:
在编译阶段,可认为class常量池包含字符串常量池,在进入虚拟机后,字符串常量池逻辑上属于运行常量池
-----------------------------------------------------------------------------------------------------------------------------------------------------
class常量池(Class Constant Pool)静态常量池
简介:
Java类被编译后,会生成一份class文件,class文件中除了类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池,存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References),
每个class文件都有一个class常量池。
内容:
字面量(又叫直接量,理解为实际值,能明确知道的值)包括:1.文本字符串 2.八种基本类型的值 3.被声明为final的常量等;
符号引用包括:1.类和方法的全限定名 2.字段的名称和描述符 3.方法的名称和描述符。
备注:
符号引用就是一个字符串,只要我们在代码中引用了一个非字面量的东西,例如引入一个框架的类,不管它是变量还是常量,在这儿都只是由一个字符串定义的符号,这个字符串存在常量池里,类加载的时候第一次加载到这个符号时,就会将这个符号引用(字符串)解析成直接引用(指针)
位置:class文件
时机:编译时
-----------------------------------------------------------------------------------------------------------------------------------------------------
运行时常量池(Runtime Constant Pool)
简介:
可以理解为class常量池被加载到内存之后的版本,不同之处是:它的字面量可以动态的添加, 符号引用会被解析为直接引用
JVM在加载类的时候,必须经过加载、验证、准备、解析... 这些阶段。
加载阶段,jvm就会将class常量池中的内容存放到运行时常量池中。
解析阶段,会把符号引用替换为直接引用,会去查询字符串常量池,以保证运行时常量池所引用的字符串与字符串常量池中是一致的。
位置:
jdk1.6 方法区
jdk1.7 堆
jdk1.8 元空间
时机:进入虚拟机运行
备注:对于习惯在HotSpot虚拟机上开发部署程序的开发者而言,方法区又叫“永久代”,仅仅是HotSpot的设计团队选择将GC分代扩展至方法区,这样就能像管理堆一样管理这部分内存,对于其他虚拟机来说是不存在“永久代”概念的。
-----------------------------------------------------------------------------------------------------------------------------------------------------
3.常量池的好处
常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。
例如字符串常量池,在编译阶段就把所有的字符串文字放到一个常量池中。
(1)节省内存空间:常量池中所有相同的字符串常量被合并,只占用一个空间。
(2)节省运行时间:比较字符串时,==比equals()快。对于两个引用变量,只用==判断引用是否相等,也就可以判断实际值是否相等。