Java常量池

Java常量池

常量池

  • 相同的值只存储一份,节省内存,共享访问,提高运行效率

基本类型的包装类

  • Boolean Byte Short Integer Long Character Float Double 八种基本类型的包装类
  • 常量值范围
    • Boolean:true, false
    • Byte Character : \u0000 - \u007f
    • Short Integer Long : -128 - 127
    • Float Double : 无常量池

==与equals()

  • 对于基本数据类型,==比较他们的数值
  • 对于对象,==比较两个对象在内存中的存放地址,可以通过重写equals()来比较两个对象的内容是否相等

字符串常量

  • Java为常量字符串建立了常量池缓存机制
    1
    2
    3
    4
    5
    6
    String s1 = "abc";
    String s2 = "ab" + "c";
    String s3 = "a" + "b" + "c"; //都是常量,是确定的,编译器将优化
    System.out.println(s1==s2); //true
    System.out.println(s1==s3); //true
    System.out.println(s2==s3); //true

基本类型的包装类和字符串的两种创建方式

  • 字面值赋值,放在栈内存(将被常量化)
    • Integer a = 1;
    • String b = "abc";
  • new对象进行创建,放在堆内存(不会常量化)
    • Integer c = new Integer(1);
    • String d = new String("abc");
  • 栈内存读取速度快,容量小
  • 堆内存读取速度慢,容量大,可以通俗的理解为Java认为new出来的对象所占内存较大(不确定,而字面值是确定的),所以需要放在堆内存

Integer常量池的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int i1 = 10;
Integer i2 = 10; //自动装箱,10本来只是int,是基本类型,而我们需要把它变成一个对象,相当于包装了一层
System.out.println(i1==i2) //true
//自动拆箱 基本类型和包装类进行比较,包装类自动拆箱

Integer i3 = new Integer(10);
System.out.println(i1==i3) //true 同理,包装类自动拆箱
System.out.println(i2==i3) //false i2,i3都是对象,而i2是常量,在常量池,i3是new出来的对象,在堆内存中

Integer i4 = new Integer(5);
Integer i5 = new Integer(5);
System.out.println(i1 == (i4+i5)); //true
System.out.println(i1 == (i4+i5)); //true
System.out.println(i1 == (i4+i5)); //true
//i4+i5的操作将会使i4,i5自动拆箱为基本类型并运算得到10,而根据之前所提到的,基本类型和包装类进行比较,包装类自动拆箱,所以都为true

Integer i6 = i4 + i5;
System.out.println(i1==i6); //true,同理i4+i5的操作使i4,i5自动拆箱,得到10,相当于Integer i6 = 10;
System.out.println(i3==i6); //false

String常量池的例子

字符串常量池存在于方法区,方法区包含的都是在整个程序中唯一的元素,如static变量

  • 一个简单的例子

    1
    2
    3
    4
    5
    6
    7
    String s1 = "abc";
    String s2 = "abc";
    String s3 = new String("abc");
    String s4 = new String("abc");
    System.out.println(s1==s2); //true 都是常量池
    System.out.println(s1==s3); //false 一个是栈内存,一个是堆内存
    System.out.println(s3==s4); //false 都是堆内存,但是不同对象
  • 图解:("'代替)

    graph LR;
    subgraph 方法区
      s['abc']
    end
    subgraph 堆
      A["s3 = new String('abc')"]
      B["s4 = new String('abc')"]
    end
    subgraph 栈
      s1
      s2
      s3
      s4
    end
    s1-->s
    s2-->s
    A-->s
    B-->s
    s3-->A
    s4-->B
  • 更为复杂的例子
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    String s5 = "abcdef";
    String s6 = s1 + "def"; //涉及到变量(不确定的),编译器不会优化
    String s7 = "abc" + "def"; //都是常量,编译器会优化成abcdef
    String s8 = "abc" + new String("def"); //涉及到new对象,编译器不优化
    System.out.println(s6==s7); //false
    System.out.println(s6==s8); //false
    System.out.println(s7==s8); //false
    System.out.println(s5==s7); //true

    String s9 = s3 + "def"; //由于s3是new的,涉及到new对象,编译器不优化
    System.out.println(s7==s9); //false
    //对于s5~s9,只有s5,s7是在常量池中,其余都在堆内存上,且地址互不相同
# Java
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×