java常量池

学习和使用java已经有4年多了,反省一下,太多关注了实际的应用层面,对某些基础的东西没有特别理解透彻。好记性不如烂笔头,记录下一些基础的知识点,把基础夯实,才能更进一步。

先引用一下java常量池的说明:
常量池在java用于保存在编译期已确定的,已编译的class文件中的一份数据。它包括了关于类,方法,接口等中的常量,也包括字符串常量,如String s = “java”这种申明方式;当然也可扩充,执行器产生的常量也会放入常量池,故认为常量池是JVM的一块特殊的内存空间。

java是一种动态链接的语言,常量池的作用非常重要,常量池中除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值外,还包含一些以文本形式出现的符号引用,比如:
类和接口的全限定名;字段的名称和描述符;方法的名称和描述符。

对于程序员来说,这样的说明略显枯燥和抽象,我们还是用代码来说明一切:

Integer i1 = new Integer(1);
Integer i2 = new Integer(1);
System.out.println(i1 == i2); // false

Integer i3 = 1;
Integer i4 = 1;
System.out.println(i3 == i4); // true

对于上面的i1和i2指向的对象,都是用new关键字来创建的,那么2个实际的对象都创建在堆内存上,就是说,i1和i2分别指向了堆内存上的2个地址,那么用==来比较的时候,肯定返回false了。对于i3和i4,是直接指定了值,这时候,java虚拟机会先到常量池里面去找,如果找到了,就返回对应的引用;如果没找到,那么就重新在堆内存上创建,类似于new。

那么,对于上面的Integer,多大的范围内数会在常量池中存在呢?我们打开Integer类的源码,发现它其实是使用了一个内部类IntegerCache来实现这个功能的:

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];
    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            int i = parseInt(integerCacheHighPropValue);
            i = Math.max(i, 127);
            // Maximum array size is Integer.MAX_VALUE
            h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
        }
        high = h;
        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
    }
    private IntegerCache() {}
}

不难看出来,当数值在-128—127的时候,会从常量池中取得。当然,我们自己写代码验证一下,会更好:

Integer i5 = 127;
Integer i6 = 127;
System.out.println(i5 == i6); // true

Integer i7 = 128;
Integer i8 = 128;
System.out.println(i7 == i8); // false

类似的,其他几种基本数据类型和对应的封装类类都有使用常量池,不过,float和double没有,其实也比较容易理解,如果这2中在常量池中要有,那要放哪些值呢?如果是Integer,那么-128—127明显比其他的值更加常用,把这些放在常量池中比较合理,但是对于浮点数,就没有明显证据表明哪几个更加常用了。

其实除了基本数据类型之外,还有一种对象在java中很常用,也会用到常量池,就是String。提到String类和常量池,必须提到String的一个native方法:intern()。intern方法会返回String对象的在常量池中的引用,如果在常量池中已经存在这个字符串了,那么直接返回这个引用;如果没有,就先把这个字符串复制到常量池,然后返回引用。依然通过代码来说明:

String s1 = new String("java");
String s2 = "java";
System.out.println(s1 == s2); // false
System.out.println(s1.intern() == s2); // true
String常量池
备注:

1、以上的源码都来自JDK1.7,不同版本的JDK可能会有不同。
2、运行环境为java自带的hotspot虚拟机,如果执行其他虚拟机,由于实现机理可能不同,运行结果也可能不同。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一.相关概念 什么是常量用final修饰的成员变量表示常量,值一旦给定就无法改变!final修饰的变量有三种:静态...
    梦工厂阅读 58,227评论 38 277
  • 相关概念 常量池的定义常量池(constant pool):指的是在编译期被确定,并被保存在已编译的.class文...
    snoweek阅读 816评论 0 4
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,766评论 18 399
  • 若要人拿真心待自己请相同的诚意对待别人 , 虽然这时代 通常他人不会同等正能量回对自己 , 对方不修德修福 , 那...
    文時衍書阅读 415评论 0 1
  • Hi,老铁们好啊,前些天说到了科隆国际游戏展这次开展了吃鸡比赛,对于绝地求生大逃杀这个游戏来说,可以说是第一次正式...
    f7246e999e03阅读 511评论 0 0