• 19、java内存分配 常量池详解


    在class文件中,“常量池”是最复杂也最值得关注的内容。 

      Java是一种动态连接的语言,常量池的作用非常重要,常量池中除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值还,还包含一些以文本形式出现的符号引用,比如: 

      类和接口的全限定名; 

      字段的名称和描述符; 

      方法和名称和描述符。 

      在C语言中,如果一个程序要调用其它库中的函数,在连接时,该函数在库中的位置(即相对于库文件开头的偏移量)会被写在程序中,在运行时,直接去这个地址调用函数; 

      而在Java语言中不是这样,一切都是动态的。编译时,如果发现对其它类方法的调用或者对其它类字段的引用的话,记录进class文件中的,只能是一个文本形式的符号引用,在连接过程中,虚拟机根据这个文本信息去查找对应的方法或字段。 

      所以,与Java语言中的所谓“常量”不同,class文件中的“常量”内容很非富,这些常量集中在class中的一个区域存放,一个紧接着一个,这里就称为“常量池”。

    转: http://hi.baidu.com/rickmeteor/blog/item/f0be11dff578ba1662279848.html

    java中的常量池技术,是为了方便快捷地创建某些对象而出现的,当需要一个对象时,就可以从池中取一个出来(如果池中没有则创建一个),则在需要重复重复创建相等变量时节省了很多时间。常量池其实也就是一个内存空间,不同于使用new关键字创建的对象所在的堆空间。本文只从java使用者的角度来探讨java常量池技术,并不涉及常量池的原理及实现方法。个人认为,如果是真的专注java,就必须对这些细节方面有一定的了解。但知道它的原理和具体的实现方法则不是必须的。

    1,常量池中对象和堆中的对象

    public class Test{

    Integer i1=new Integer(1);
       Integer i2=new Integer(1);
    //i1,i2分别位于堆中不同的内存空间

       System.out.println(i1==i2);//输出false


       Integer i3=1;
       Integer i4=1;
    //i3,i4指向常量池中同一个内存空间

       System.out.println(i3==i4);//输出true

    //很显然,i1,i3位于不同的内存空间

    System.out.println(i1==i3);//输出false

    }

    2,8种基本类型的包装类和对象池

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

    public class Test{

    public static void main(String[] args){

       //5种整形的包装类Byte,Short,Integer,Long,Character的对象,

       //在值小于127时可以使用常量池

       Integer i1=127;

       Integer i2=127;

       System.out.println(i1==i2)//输出true

       //值大于127时,不会从常量池中取对象

       Integer i3=128;

       Integer i4=128;

       System.out.println(i3==i4)//输出false

       //Boolean类也实现了常量池技术

       Boolean bool1=true;

       Boolean bool2=true;

       System.out.println(bool1==bool2);//输出true

       //浮点类型的包装类没有实现常量池技术

       Double d1=1.0;

       Double d2=1.0;

       System.out.println(d1==d2)//输出false

      

    }

    }

    3,String也实现了常量池技术

    String类也是java中用得多的类,同样为了创建String对象的方便,也实现了常量池的技术,测试代码如下:

    public class Test{

    public static void main(String[] args){

    //s1,s2分别位于堆中不同空间

    String s1=new String("hello");

    String s2=new String("hello");

    System.out.println(s1==s2)//输出false

    //s3,s4位于池中同一空间

    String s3="hello";

    String s4="hello";

    System.out.println(s3==s4);//输出true

    }

    }

    最后:

    细节决定成败,写代码更是如此。

    对Integer对象的补充:http://hi.baidu.com/fandywang_jlu/blog/item/c5590b4eae053cc3d1c86a13.html

    Integer的封装吧:

       public static Integer valueOf(int i) {

             final int offset = 128;

             if (i >= -128 && i <= 127) { // must cache

                return IntegerCache.cache[i + offset];

             }

              return new Integer(i);

           }
    当你直接给一个Integer对象一个int值的时候,其实它调用了valueOf方法,然后你赋的这个值很特别,是128,那么没有进行cache方法,相当于new了两个新对象。所以问题中定义a、b的两句代码就类似于:

          Integer a = new Integer(128);

          Integer b = new Integer(128);
    这个时候再问你,输出结果是什么?你就知道是false了。如果把这个数换成127,再执行:

          Integer a = 127;

          Integer b = 127;

          System.out.println(a == b);
    结果就是:true

    由上可知,我们进行对象比较时最好还是使用equals,便于按照自己的目的进行控制。

    --------------------------------------------------补充-----------------------------------------------------------------------

       我们看一下IntegerCache这个类里面的内容:

       private static class IntegerCache {

          private IntegerCache() {

          }

          static final Integer cache[] = new Integer[-(-128) + 127 + 1];

          static {

             for (int i = 0; i < cache.length; i++)

                cache[i] = new Integer(i - 128);

          }

       }

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

  • 相关阅读:
    MFC Windows 程序设计>WinMain 简单Windows程序 命令行编译
    AT3949 [AGC022D] Shopping 题解
    CF643D Bearish Fanpages 题解
    CF643C Levels and Regions 题解
    CF241E Flights 题解
    CF671C Ultimate Weirdness of an Array 题解
    CF1592F Alice and Recoloring 题解
    GYM 102452E 题解
    CF494C Helping People 题解
    P5556 圣剑护符
  • 原文地址:https://www.cnblogs.com/caoyc/p/4543757.html
Copyright © 2020-2023  润新知