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

    Java中的常量池

    Java常量池实际上分为两种形态:静态常量池和运行时常量池
        常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。
    
    
    静态常量池:
    
        静态常量池是Class文件常量池(编译后的class文件的常量池),存放各个字面量值,符号引用的数据。
    
        主要用于存放两大类常量:字面量(Literal)和符号引用量(Symbolic References)。
    
        字面量相当于Java语言层面常量的概念,如文本字符串,声明为final的常量值等。
    
    
    运行时常量池(具备动态性):
    
        是jvm虚拟机在完成类装载操作后,将class文件中的常量池载入到内存的方法区中。
    
        我们常说的常量池,就是指方法区中的运行时常量池。
    

    字符串示例

    String s1 = "Hello";
    String s2 = "Hello";
    String s3 = "Hel" + "lo";
    String s4 = "Hel" + new String("lo");
    String s5 = new String("Hello");
    String s6 = s5.intern();
    String s7 = "H";
    String s8 = "ello";
    String s9 = s7 + s8;
    
    
    System.out.println(s1 == s2);  // true
    
    //所有参与拼接的部分都是已知的字面量,在编译期间,这种拼接会被优化,编译器直接帮你拼好
    System.out.println(s1 == s3);  // true
    
    //对于所有包含new方式新建对象(包括null)的“+”连接表达式,它所产生的新对象都不会被加入字符串池中
    System.out.println(s1 == s4);  // false
    
    //s7、s8作为两个变量,都是不可预料的,编译器毕竟是编译器,不可能当解释器用,不能在编译期被确定
    //所以不做优化,只能等到运行时,在堆中创建s7、s8拼接成的新字符串,在堆中地址不确定,不可能与方法区常量池中的s1地址相同
    System.out.println(s1 == s9);  // false
    
    //二者都在堆中,但地址不同
    System.out.println(s4 == s5);  // false
    
    //s5在堆中,内容为Hello ,intern方法会尝试将Hello字符串添加到常量池中,并返回其在常量池中的地址
    //因为常量池中已经有了Hello字符串,所以intern方法直接返回地址
    System.out.println(s1 == s6);  // true
    
    
    特例一
    
    public static final String A = "ab"; // 常量A
    public static final String B = "cd"; // 常量B
         String s = A + B;    // 将两个常量用+连接对s进行初始化 
         String t = "abcd";    //s == t 成立
    A和B都是常量,值是固定的,因此s的值也是固定的,它在类被编译时就已经确定了。
    也就是说:String s=A+B; 等同于:String s="ab"+"cd";
    
    
    特例二
    
        public static final String a;
        public static final String b;
    
        static {
            a = "123";
            b = "456";
        }
    
        public static void main(String[] args)
        {
            String c = "123456";
            String d = a + b;
            System.out.println(c == d);
        }
    
    编译期间,就已经确定了c,放在字符串常量池(堆中),但编译期static不执行的,a和b的值是未知的,
    static代码块,在初始化的时候被执行,初始化属于类加载的一部分,属于运行时常量池(方法区中)。
    运行时是这样的String s6=new StringBuilder().append(s3).append(s4).toString();这里的过程是通过StringBuilder这个类实现的
    它是通过new String()的方式来作为值进行返回的,所以是在堆中开辟的一块空间。所以和常量池中的不一样
    
    1,在java 中,直接使用==操作符,比较的是两个字符串的引用地址,并不是比较内容,比较内容请用String.equals()
    
    2,程序运行时,除非手动向常量池中添加常量(比如调用intern方法),否则jvm不会自动添加常量到常量池。
    

    整型常量池、浮点型常量池等

    Byte,Short,Integer,Long,Character,Boolean都实现了常量池技术
    
    数值类型的常量池不可以手动添加常量,程序启动时常量池中的常量就已经确定了,
        比如整型常量池中的常量范围:-128~127,
        Byte,Short,Integer,Long,Character,Boolean这5种包装类默认创建了数值[-128,127]的相应类型的缓存数据,
        但是超出此范围仍然会去创建新的对象
    
    -128到127之 间的Integer会缓存到一个Integer数组中去了:
        如果你要把一个int变成一个Integer对象,首先去缓存中找,找到的话直接返回引用给你,不必再新new一个,
        如果不在-128-IntegerCache.high(127) 时会返回一个新new出来的Integer对象
    
    Integer源码,里面有个静态类IntegerCache
    它对Integer进行了缓存,范围是[-128,127],只要是这个范围内的数字都会缓存到这个里面,做成常量池进行管理
    
    
    private static class IntegerCache {
        static final int high;
        static final Integer cache[];
    
        static {
            final int low = -128;
            // high value may be configured by property
            int h = 127;
            if (integerCacheHighPropValue != null) {
                // Use Long.decode here to avoid invoking methods that
                // require Integer's autoboxing cache to be initialized
                int i = Long.decode(integerCacheHighPropValue).intValue();
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - -low);
            }
            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() {
        }
    }
    

    字符串常量池(String Constant Pool)

    存储编译期类中产生的字符串类型数据
    
    JDK6.0及之前版本,字符串常量池是放在Perm Gen区(也就是方法区)中
    JDK7.0版本,字符串常量池被移到了堆中了
    
    运行时常量池和字符串常量池是独立的
    
    String.intern()
    检查字符串常量池中是否存在String并返回池里的字符串引用
    若池中不存在,则将其加入池中,并返回其引用。 
    这样做主要是为了避免在堆中不断地创建新的字符串对象
    

    class常量池(Class Constant Pool)

    每一个Java类被编译后,就会形成一份class文件
    
    class文件中除了包含类的版本、字段、方法、接口等描述信息外
    
    还有一项信息就是常量池(constant pool table),用于存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References)
    

    运行时常量池(Runtime Constant Pool)

    运行时常量池包含了类的运行时常量和静态方法等Class常量池的数据
    
    JVM中运行时常量池在方法区中,是class常量池被加载到内存之后的版本
    
    当类加载到内存中后,jvm就会将class常量池中的内容存放到运行时常量池中
    
    运行时常量池和字符串常量池是独立的
    

    new关键字

    使用new关键字当然是每次都是新建一个,分配自己的空间
  • 相关阅读:
    CSS的浮动和清除
    外边距合并现象
    CSS 盒子模型
    CSS样式三
    CSS的继承与优先级
    CSS 样式二
    UVA 11922 Permutation Transformer(平衡二叉树)
    HDU 3726 Graph and Queries(平衡二叉树)(2010 Asia Tianjin Regional Contest)
    POJ 1873 The Fortified Forest(枚举+凸包)
    POJ 2069 Super Star(计算几何の最小球包含+模拟退火)
  • 原文地址:https://www.cnblogs.com/loveer/p/11519739.html
Copyright © 2011-2022 走看看