当前位置:   article > 正文

JAVA常量池和在基本数据类型包装器类及String的应用_java常量池只能引到基本类型和string

java常量池只能引到基本类型和string

对于基本数据类型,java内有封装的包装器类,分别对应8个基本数据类型,Boolean,Byte,Short,Integer,Long,Character,Float和Double。

其中,除了Float和Double,其他6个类型都具有常量池,即被赋值为一个常量后,只在栈中存一份,共享访问。

常量池存在一定的赋值数据限制:

Boolean:true,false
Byte:-127~128
Character:0~127
Short,Integer,Long:-128~127
Float,Double:无常量池

我们看如下代码:

Integer i1 = 10;
Integer i2 = new Integer(10);
Integer i3 = 10;
Integer i4 = new Integer(10);
int i5 = 10;
  • 1
  • 2
  • 3
  • 4
  • 5

Java中,当定义一个类对象,并赋值给它,意思是在内存中开辟一段空间,然后让这个类对象作为引用指向这个空间。

我们知道,用new来构造,是在堆里建立一个内存空间,然后类引用类型指向这个空间,每个空间是相互独立的,即i2和i4,指向两个不同空间。每new一个对象,都会新在堆上开辟一个内存空间,然后引用类型指向它。
而常量池的概念,就是满足一定条件的赋值方式,如i1和i3,会共享指向同一个常量栈空间。以后对再多的包装器类赋值同样的常量,都会指向这同一个空间。这样的作用是一定程度地减少类对象的创建和销毁。
i5直接就是一个值,不是一个类,不是引用类型,按值比较。

我们可以理解为如下图(手画略丑):
在这里插入图片描述
图中,10外面一个方框代表对10进行封装成的包装器类Integer的一个内存块。对一个包装器类,新new一个10,则会多一个相互独立的内存块在堆里,而新等号赋值一个10,则多一个引用类型指向栈中那同一个内存块。

可以看出,
i1 == i3, true;
i2 == i4, false;
i3 == i4, false;
i1 == i5,ture;(这里比较的是值,看下文)

需要注意的是,基本变量类,在构造的时候,会被装箱成类,在运算的时候(包括==),会被开箱成数字,而类和类的==比较,比较的是地址,类和基本类型的比较,比较的是值,因为类会开箱成基本类型。

我们可以看下一段代码

import java.util.*;
public class Practice {
    public static void main(String[] args) {
        int i1 = 10;
        Integer i2 = 10;
        Integer i3 = 10;
        Integer i4 = new Integer(10);
        Integer i5 = new Integer(5);
        Integer i6 = new Integer(5);
        Integer i7 = 5;
        System.out.println(i1 == i2);
        System.out.println(i2 == i3);
        System.out.println(i3 == i4);
        System.out.println(i3 == i5 + i6);
        System.out.println(i4 == i5 + i6);
        System.out.println(i5 == i6);
        System.out.println(i4 == i7 + i5);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

得到的结果是

true
true
false
true
true
false
true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

总结下来,我们也可以得到三条重要规则:

  1. 一旦参与运算,包装器类就会开箱,用值参与运算;
  2. 运算式中只要有值相加减乘除等等,那么就用值参与运算比较;
  3. 运算式中如果直接比较引用,没有值参与,那就是用地址参与比较。

但是值得注意的是,如果是两个类进行运算得到了另一个类,把另一个类进行比较,那还是比较的是地址,可以看如下代码:

import java.util.*;
public class Practice {
    public static void main(String[] args) {
        String s = "abc";
        String s1 = new String("def");
        String s2 = "abcdef";
        String s3 = s + s1;
        String s4 = "def";
        String s5 = s + s4;
        String s6 = "abc" + "def";
        System.out.println(s + s1 == s2);
        System.out.println(s + s1 == s3);
        System.out.println(s + new String("def") == s3);
        System.out.println(s5 == s2);
        System.out.println(s6 == s2);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

运行结果是

false
false
false
false
true
  • 1
  • 2
  • 3
  • 4
  • 5

其中,对String有两种赋值方法,一种是直接赋值一个常量,栈分配内存;另一种是new一个String,堆分配内存。

从这里我们可以看出:

  1. 如s3,s5,以及第一和第二个输出语句中,只要赋值语句中涉及到的包括不是常量的量,比如一个String类实例,或者直接一个new,这些编译器不会帮忙优化,所以比较的还是地址。
  2. 如s6,s2这种,赋值直接是用常量赋值的,编译器则会帮忙用常量池进行优化,所以指向的是同一个地址。
  3. 这里我们比较的是String类引用类型,所以这段代码里面比较的所有都是地址,不是值比较,最后一个是true的原因是两个地址相同,而不是因为值相同。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/631944
推荐阅读
相关标签
  

闽ICP备14008679号