Java 常量池

Java 常量池

常量池入口放置 u2类型的数据,代表常量池容量计数值 constant_pool_count 。 u2类型是 什么

基本类型包装类和常量池

  1. Byte Short Integer, Long Character, Boolean:

Integer如果超过范围 就会去创建新的对象

  Integer i1 = 40;
  Integer i2 = 40;

 Integer i3 = 400;
 Integer i4 = 400;

  System.out.println(i1 == i2);   //true
 System.out.println(i3 == i4);   //false 


        double d1 = 1.1;
        double d2 = 1.1;

        Double d3 = 1.1;
        Double d4 = 1.1;
        System.out.println(d1 == d2); // true
        System.out.println(d3 == d4); // false

两种浮点数类型的包装类Float,Double并没有实现常量池技术。

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

Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;

Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);

System.out.println("i1 = i2\t"+ (i1==i2));               //true
System.out.println("i1 = i2 + i3\t"+ (i1 == (i2 + i3))); //true
System.out.println("i4 = i5\t"+ (i4==i5));               //false
System.out.println("i4 = i5 + i6\t"+ (i4 ==i5 + i6));     //true
System.out.println("40 = i5 + i6 "+ (40 == i5+i6));       // true

首先i5和i6进行自动拆箱操作,进行数值相加,即i4 == 40。
然后Integer对象无法与数值进行直接比较,所以i4自动拆箱转为int值40,最终这条语句转为40 == 40进行数值比较。

String类和对象池

String s1 = "hello";
String s2 = new String("hello");

System.out.println(s1 == s2);   //false

s1 常量池 中对象; s2 在堆上创建 新对象。

String s3 = "hello";
String s4 = "world";
String s5 = "helloworld";
String s6 = s3+s4;

System.out.println(s5 == s6); //false

String 重载了 + 操作符 字符串拼接相当于 重新创建新的字符串。 因此, "hello" + "world" 相当于创建 新的 "helloworld"

java基础:字符串的拼接 http://www.jianshu.com/p/88aa19fc21c6

    public static final String S7 = "ab";
    public static final String S8 = "cd";

    public static void main(String[] args){

        String s9 = "abcd";

        System.out.println(s9 == (S7+S8));  //true
    }

S7 S8为常量。 编译时确定。

    public static final String S7;
    public static final String S8; 

    static {
        S7 = "ab";
        S8 = "cd";
    }

    public static void main(String[] args){

        String s9 = "abcd";

        System.out.println(s9 == (S7+S8));// false

    }


// 此时,由于 S7 S8没有 定义时赋值, 相当于 变量,值在运行时确定。而不是编译时。

String s1 = new String("xyz");

1.类加载,一个类只进行一次。 "xyz"在类加载时就已经创建并驻留了(如果该类被加载之前已经有"xyz"字符串被驻留过则不需要重复创建用于驻留的"xyz"实例)。
驻留的字符串是放在全局共享的字符串常量池中的。
2.在这段代码后续被运行的时候,"xyz"字面量对应的String实例已经固定了,不会再被重复创建。

所以这段代码将常量池中的对象复制一份放到heap中,并且把heap中的这个对象的引用交给s1 持有。

这条语句创建了2个对象。 一个堆上的对象,一个引用对象 ?

String 常量池 String.intern()用法

  • 直接使用双引号声明出来的String对象会直接存储在常量池中。
  • 如果不是用双引号声明的String对象,可以使用String提供的intern方法。intern 方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中
//Other.java
package basics.other;

public class Other {
    public static String hello = "hello";
}


//StringTest.java
package basics;
public class StringTest {
    public static void main(String[] args){
        String hello = "hello";
        String lo    = "lo";
        System.out.println(hello == "hello");                   //true
        System.out.println(basics.other.Other.hello == hello); //true
        System.out.println(Other.hello == hello);            //ture
        System.out.println(hello == "hel"+"lo");            //true
        System.out.println(hello == "hel"+lo);             //false
        System.out.println(hello == ("hel"+lo).intern());  //true
    }
}
class Other{
    static String hello = "hello";

}

在同包同类下,引用自同一String对象.
在同包不同类下,引用自同一String对象.
在不同包不同类下,依然引用自同一String对象.
在编译成.class时能够识别为同一字符串的,自动优化成常量,引用自同一String对象.
在运行时创建的字符串具有独立的内存地址,所以不引用自同一String对象. “+” 操作符 创建新对象。

《深入Java虚拟机 》 第6章 Java class文件
《深入理解Java7》 第8章 Java源代码和字节代码操作
《深入理解Java虚拟机 JVM高级特性与最佳实践》6.3

参考资料

http://www.jianshu.com/p/c7f47de2ee80

Java中的自动装箱与拆箱
http://droidyue.com/blog/2015/04/07/autoboxing-and-autounboxing-in-java/

Java堆、栈和常量池以及相关String的详细讲解(经典中的经典) (未看)
http://www.cnblogs.com/xiohao/p/4296088.html

深入解析String#intern
http://tech.meituan.com/in_depth_understanding_string_intern.html

posted @ 2017-02-11 10:55  ironbrady  阅读(216)  评论(0编辑  收藏  举报