zoukankan      html  css  js  c++  java
  • 常量池

    Java中的常量池技术,是为了方便快捷地创建某些对象而出现的,当需要一个对象时,就可以从池中取一个出来(如果池中没有则创建一个),则在需要重复重复创建相等变量时节省了很多时间。常量池其实也就是一个内存空间,不同于使用new关键字创建的对象所在的堆空间。

    常量池项共分为11种类型:

    常量池项类型  值  说明 
    CONSTANT_Utf8  UTF-8编码的Unicode字符串 
    CONSTANT_Integer  int型常量 
    CONSTANT_Float  Float型常量 
    CONSTANT_Long  Long型常量 
    CONSTANT_Double double型常量 
    CONSTANT_Class   对一个class的符号引用 
    CONSTANT_String  String型常量 
    CONSTANT_Fieldref  对一个字段的符号引用  
    CONSTANT_Methodref  10  对一个类方法的符号引用 
    CONSTANT_InterfaceMedthodref  11  对一个接口方法的符号引用 
    CONSTANT_NameAndType 12  对名称和类型的符号引用 

    例子1:常量池中对象和堆中的对象

     1 Integer i1 = new Integer(1);
     2 Integer i2 = new Integer(1);
     3 // i1,i2分别位于堆中不同的内存空间
     4 System.out.println(i1 == i2);// 输出false
     5  
     6 Integer i3 = 1;
     7 Integer i4 = 1;
     8 // i3,i4指向常量池中同一个内存空间
     9 System.out.println(i3 == i4);// 输出true
    10  
    11 // 很显然,i1,i3位于不同的内存空间
    12 System.out.println(i1 == i3);// 输出false

    例子2:

    Java中基本类型的包装类的大部分都实现了常量池技术,这些类是Byte,Short,Integer,Long,Character,Boolean,另外两种浮点数类型的包装类则没有实现。另外Byte,Short,Integer,Long,Character 这5种整型的包装类也只是在对应值小于等于127时才可使用对象池,也即对象不负责创建和管理大于127的这些类的对象。

     1 // 5种整形的包装类Byte,Short,Integer,Long,Character的对象,
     2 // 在值小于127时可以使用常量池
     3 Integer i1 = 127;
     4 Integer i2 = 127;
     5 System.out.println(i1 == i2);// 输出true
     6  
     7 // 值大于127时,不会从常量池中取对象
     8 Integer i3 = 128;
     9 Integer i4 = 128;
    10 System.out.println(i3 == i4);// 输出false
    11  
    12 // Boolean类也实现了常量池技术
    13 Boolean bool1 = true;
    14 Boolean bool2 = true;
    15 System.out.println(bool1 == bool2);// 输出true
    16  
    17 // 浮点类型的包装类没有实现常量池技术
    18 Double d1 = 1.0;
    19 Double d2 = 1.0;
    20 System.out.println(d1 == d2);// 输出false

    例子3:同样的,String也实现了常量池技术

    1 // s1,s2分别位于堆中不同空间
    2 String str1 = new String("hello");
    3 String str2 = new String("hello");
    4 System.out.println(str1 == str2);// 输出false
    5  
    6 // s3,s4位于池中同一空间
    7 String str3 = "hello";
    8 String str4 = "hello";
    9 System.out.println(str3 == str4);// 输出true

    例子4:关于Integer类的valueOf方法的一个小问题

    1 //代码段A
    2 Integer a1 = 127;
    3 Integer b1 = 127;
    4 System.out.println(a1 == b1);//输出true
    5 //代码段B
    6 Integer a2 = 128;
    7 Integer b2 = 128;
    8 System.out.println(a2 == b2);//输出false

    原因:当你直接给一个Integer对象一个int值的时候,实际上却自动调用了valueOf方法,然而valueOf方法的内部实现是这样的:

    1 public static Integer valueOf(int i) {
    2     final int offset = 128;
    3     if (i >= -128 && i <= 127) {
    4         return IntegerCache.cache[i + offset];
    5     }
    6     return new Integer(i);
    7 }

    因为代码段B里赋予的值128溢出了,没有进入if (i >= -128 && i <= 127)条件语句,返回IntegerCache 类的静态数组的数据,IntegerCache类的内部实现是这样的:

    1 private static class IntegerCache {
    2     private IntegerCache() {
    3     }
    4     static final Integer cache[] = new Integer[-(-128) + 127 + 1];
    5      
    6     static {
    7         for (int i = 0; i < cache.length; i++)
    8             cache[i] = new Integer(i - 128);
    9     }

    而是直接执行了return new Integer(i)语句,又重新new了一个Integer对象出来,即代码段B实际上就相当于:

    1 Integer a2 = new Integer(128);
    2 Integer b2 = new Integer(128);

    补充说明:关于上文提到的IntegerCache类,由于cache[]在IntegerCache类中是静态数组,也就是只需要初始化一次,即static{……}部分,所以,如果Integer对象初始化时是-128~127的范围,就不需要再重新定义申请空间,都是同一个对象—在IntegerCache.cache中,这样可以在一定程度上提高效率。


    例子5:关于String类的intern方法

    当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并返回此 String 对象的引用。

    它遵循以下规则:对于任意两个字符串s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern()才为true。

    例如:

     1 String str1 = new String("abc");
     2 String str2 = str1.intern();
     3 if (str1 == str2) {
     4     System.out.println("字符串abc在常量池中");
     5 } else {
     6     System.out.println("字符串abc不在常量池中");
     7 }
     8  
     9 String str3 = "abc";
    10 String str4 = str3.intern();
    11 if (str3 == str4) {
    12     System.out.println("字符串abc在常量池中");
    13 } else {
    14     System.out.println("字符串abc不在常量池中");
    15 }

    还有,

    1 String str1 = "abc";
    2 String str2 = new String("abc");
    3 String str3 = new String("abc");
    4 str2.intern();// 不起作用的代码
    5 str3 = str3.intern();// 起作用
    6 System.out.println(str1 == str2);// 输出:false
    7 System.out.println(str1 == str2.intern());// 输出:true
    8 System.out.println(str1 == str3);// 输出:true
  • 相关阅读:
    使Eclipse下支持编写HTML/JS/CSS/JSP页面的自动提示
    SpringMVC与Struts2的对比
    事务不提交,也有可能写redo和数据文件
    14.4.1 InnoDB Startup Configuration
    SLB 权重问题
    perl 访问网站一些useragent的设置
    14.3.5.3 How to Minimize and Handle Deadlocks 如何减少和处理死锁
    nginx 区分pc和mobile 到不同的404页面
    dokcer 运行和进入容器
    docker 私有仓库查询
  • 原文地址:https://www.cnblogs.com/xianDan/p/4292814.html
Copyright © 2011-2022 走看看