【JVM】常量池

常量池(Runtime Constant Poo)

常量池Java中可以分为三种:字符串常量池(堆)、Class文件常量池、运行时常量池(堆)。

1.字符串常量池(String Pool)

  • 为了提升性能和减少内存消耗针对字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。
  • 字符串常量池是所有类公用的一块空间,在一个虚拟机中只有一块常量池区域。
  • 字符串常量池存在于堆上。
  • 用来存储一些全局的字符串对象的引用
  • 中生成字符串对象实例,然后将该字符串对象实例的引用值存到字符串常量池中。

2.Class文件常量池(Class Constant Pool)

  • .java文件在通过javac编译后会生成.class文件。
  • Class文件中存放类的版本、字段、方法、接口等描述信息外,还有一项是常量池。
  • 常量池用于存放编译期间生产的各种字面量和符号引用。
  • 每个类都有一个Class文件常量池。

3.运行时常量池(Runtime Constant Pool)

  • JDK1.7及之后版本的 JVM 已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池。
  • 在类加载后将存Class文件常量池的内容加载到运行时常量池。
  • 每个类都有一个运行时常量池。
  • 当常量池无法再申请到内存时会抛出OutMemoryError异常。
    【JVM】常量池_第1张图片
    4.举例
  • 基本类型的包装类的大部分都实现了常量池技术,即Byte,Short,Integer,Long,Character,Boolean;数值[-128,127]的相应类型的缓存数据,但是超出此范围仍然会去创建新的对象。
  • 两种浮点数类型的包装类 Float,Double 并没有实现常量池技术。
Double d3 = 1.2;
Double d4 = 1.2;
System.out.println(d3 == d4);  // false

Integer i1= 40// Java在编译的时候会直接将代码封装成Integer i1=Integer.valueOf(40);,从而使用常量池中的对象。
Integer i2 = new Integer(40); // 这种情况下会创建新的对象,所以尽量避免使用这种方式。
System.out.println(i1 == i2);  // false
String str1 = "abcd";              // 直接使用双引号声明出来的String对象会直接存储在常量池中
String str2 = new String("abcd");  // 堆内存空间创建一个新的对象,str2指向堆对象
String str3 = str2.intern();       // intern()如果运行时常量池中已经包含一个等于此String对象内容的字符串,则返回常量池中该字符串的引用;如果没有,则在常量池中创建与此 String 内容相同的字符串,并返回常量池中创建的字符串的引用。
String str4 = str1.intern();

System.out.println(str1 == str2);  // false
System.out.println(str2 == str3);  // false
System.out.println(str1 == str3);  // true
System.out.println(str2 == str3);  // false
System.out.println(str2 == str4);  // false
System.out.println(str3 == str4);  // true
/**
* String str2 = new String("abcd"); 创建了两个对象
* 字符串常量在编译期确定放入常量池,堆上的对象在运行期初始化阶段确定
*/
String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing"; //常量池中的对象
String str4 = str1 + str2; //在堆上创建的新的对象     
String str5 = "string";    //常量池中的对象
System.out.println(str3 == str4);  // false
System.out.println(str3 == str5);  // true
Integer i1 = 40// Java在编译的时候会直接将代码封装成Integer i1=Integer.valueOf(40);,从而使用常量池中的对象。
Integer i2 = new Integer(40);  // 创建新的对象,所以尽量避免使用这种方式。
Integer i3 = new Integer(40); 
Integer i4 = new Integer(0); 
System.out.println(i2 == i3);       // false
System.out.println(i2 == i3 + i4);  // true,Integer对象不适用 + 操作符,会先进行自动拆箱操作,再进行数值相加。Integer对象无法与数值进行直接比较,所以i2自动拆箱转为int值40,最终这条语句转为40 == 40进行数值比较。
System.out.println(40 == i3 + i4);  // true

参考:
http://tangxman.github.io/2015/07/27/the-difference-of-java-string-pool/

你可能感兴趣的:(JVM,jvm,java,开发语言)