Java数据类型及String的缓冲池

Integer

Integer x = new Integer(123);
Integer y = new Integer(123); 
System.out.println(x == y); // false
Integer z = Integer.valueOf(123); 
Integer k = Integer.valueOf(123); 
System.out.println(z == k); // true

new Integer(123)与Integer.valueOf(123)的区别在于:

  • new Integer(123)每次都会创建一个对象
  • Integer.valueOf(123)会使用缓存池中的对象,多次调用会取得同一个对象的引用
  • valueOf() 方法的实现比较简单,就是先判断值是否在缓存池中,如果在的话就直接返回缓存池的内容。在 Java 8 中,Integer 缓存池的大小默认为 -128~127。
  • 编译器会在自动装箱过程调用 valueOf() 方法,因此多个值相同且值在缓存池范围内的 Integer 实例使用自动装箱来
    创建,那么就会引用相同的对象。
Integer m = 123;
Integer n = 123;
System.out.println(m == n); // true

基本类型对应的缓冲池如下:

  • boolean values true and false;
  • all byte values;
  • short values between -128~127;
  • int values between -128~127;
  • char int the range \u0000 to \u007F
    注意;在使用这些基本类型对应的包装类型时,如果该数值在缓冲范围内,就可以直接使用缓冲池中的对象
    在jdk1.8的所有的数值缓冲池中,Integer的缓冲池IntegerCache很特殊,因为这个缓冲池的下届是-128,上届默认是127,但是上届是可调的,在启动JVM的时候,通过-XX:AutoBoxCacheMax=来指定这个缓冲池的大小,该选项在JVM初始化的时候会设定一个名为java.lang.IntegerCache.high系统属性,然后IntegerCache初始化的时候就会读取该系统属性来决定上届。

String

String被声明为final,因此它不可被继承。
在java8中,String内部使用char数组存数据。
在这里插入图片描述
在java9之后,String类的实现改用byte数组存储字符串,同时使用coder来标识使用了那种编码。
在这里插入图片描述
value数组被声明final,这意味着value数组初始化之后就不能再引用其他数组。并且String内部没有改变value数组的方法,因此可以保证String不可变。
String的value数组不可变的好处:

  • 可以缓存hash值
    因为String的hash值经常被使用,例如String用做hashMap的key。不可变的特性使得hash值页不可变,因此只需要进行一次计算。

  • String Pool的需要
    如果一个String对象已经被创建过了,那么就会从String Pool中取得引用。只有String是不可变的,才可能使用String Pool。
    在这里插入图片描述

  • 安全性
    String经常作为参数,Sting不可变性可以保证参数不可变。例如在作为网络连接参数的情况下如果String是可变的,那么在网络连接过程中,String被改变,改变String对象的哪一方以为现在连接的是其他主机,而实际情况却是不一定是。

  • 线程安全
    String不可变性天生具备线程安全,可以在多个线程中安全的使用。

String,StringBuffer and StringBuilder

  1. 可变性
    ①String不可变
    ②StringBuffer和StringBuilder可变

  2. 线程安全
    ①String不可变,因此线程安全
    ②StringBuilder不是线程安全的
    ③StringBuffer是线程安全的,内部使用的sychronized进行同步

    String Pool
    字符串常量池(String Pool)保存着所有字符串字面量,这些字面量在编译时期就确定,不仅如此,还可以使用Sting的intern()方法在运行过程中将字符串添加到、String pool中。
    当一个字符串调用intern()方法时,如果String Pool中已经存在一个字符串和该字符串值相等)(使用equals()方法进行确定),那么就会返回String Pool中字符串的引用;否则,就会在String Pool中添加一个新的字符串的引用。

    举个栗子:

String s1 = new String("aaa");
 String s2 = new String("aaa"); 
 System.out.println(s1 == s2); // false
  String s3 = s1.intern(); 
  String s4 = s1.intern(); 
  System.out.println(s3 == s4); // true

在上面这个栗子中,s1和s2采用new String()的方式新建了两个不同字符串,所以返回的两个引用不相等;但是调用intern()方法会将s1这个字符串添加到String Pool中,然后返回String Pool中这个字符串的引用,则为s3,当第二次调用intern()方法是,String Pool中已经存在这个字符串了,直接返回其引用,所以两次的引用相同,即s3与s4相同。
**注意:**如果采用的是下面这种方式,则会自动放入到String Pool中的

String s5 = "bbb"; 
String s6 = "bbb"; 
System.out.println(s5 == s6); // true

在 Java 7 之前,String Pool 被放在运行时常量池中,它属于永久代。而在 Java 7,String Pool 被移到堆中。这是因为永久代的空间有限,在大量使用字符串的场景下会导致 OutOfMemoryError 错误。

new String(“abc”)
使用这种方式一共会创建两个字符串对象(前提是String Pool中还没有“”abc“”字符串对象)。

  • “”abc“”属于字符串字面量,因此编译时期会在String Pool中创建一个字符串对象,指向这个“”abc“”字符串字面量
  • 而使用new的方式会在堆中创建一个字符串对象

在这里插入图片描述
在这里插入图片描述
在 Constant Pool 中,#19 存储这字符串字面量 “abc”,#3 是 String Pool 的字符串对象,它指向 #19 这个字符串字面量。在 main 方法中,0: 行使用 new #2 在堆中创建一个字符串对象,并且使用 ldc #3 将 String Pool 中的字符串对象作为 String 构造函数的参数。
以下是 String 构造函数的源码,可以看到,在将一个字符串对象作为另一个字符串对象的构造函数参数时,并不会完全复制 value 数组内容,而是都会指向同一个 value 数组。

public String(String original) {
 		this.value = original.value;
  		this.hash = original.hash; 
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值