[java] String探秘

String类

由于我们每天都在和String打交道,他已经重要的让我们无法感知它的存在,正因如此,他的性能问题也最容易被忽视。下面让我们从源码的角度来看看,String类有哪些奥秘。(以下代码使用jdk1.8)

1. 存储结构

首先可以看到,String存储结构是char数组。

private final char value[];

2. 不可变

可以看到,String类本身以及其属性都是final的,为什么呢?

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0
  1. 如果String类本身不是final,那么很可能通过继承而被修改。
  2. hash属性不更改确保了唯一性。
  3. value不变是为了实现字符串常量池,避免相同字符串的重复创建

这里可能有一个误区,刚学习Java的同学可能会说,下面的代码没有问题,变量a的值变了啊???

String a = "abc";
a = "efg";

在Java中,一切都是引用,类似于c语言中的指针。这里面a就是一个引用,而“abc”,“efg”是放在堆中的常量池的。在上面的代码中,a一开始指向常量池中的“abc”,后来指向了“efg”,“abc”还在常量池中呆着,并没有变,等待下一轮GC,被垃圾收集处理掉。

在这里,如果将a声明为final的话,说明这个引用是不可变的,上面的代码就出问题了。

3. String对象的优化

1) 字符串拼接

在阿里巴巴Java开发手册1.4节17条明确规定,在循环体内的连接方式要使用StringBuilder的append方法进行拓展。

其实在编译期,编译器会对代码进行优化,自动拼接字符串常量。那么对于变量,则优化为StringBuilder方式,但是问题来了,在循环体内,就会生成n个StringBuilder对象,代码如下。

String str = "abcdef";
for(int i=0; i<1000; i++) {
      str = str + i;
}

// 编译优化
String str = "abcdef";
for(int i=0; i<1000; i++) {
            str = (new StringBuilder(String.valueOf(str))).append(i).toString();
}

所以,在循环体内一定要用显示StringBuilder的方式拼接字符串,提升性能。

2) intern方法

我们可以看到intern是个本地方法。

public native String intern();

前面我们说到,String类的存储不可变性是为了实现常量池,实现字符串的复用。在每次赋值的时候使用intern方法,如果常量池中有相同的值,就返回常量池中字符串对象的引用,如果没有,就把字符串的引用添加到常量池中,返回常量池中的字符串引用。

举个栗子,“abc”是常量,在编译期就放入了常量池。在运行时,a指向常量池中的字符串引用。new String会在堆中创建一个String对象,并返回String对象的引用。当调用了intern方法时,c会到常量池中查找是否有相同的字符串,有则返回它的引用。

String a = "abc";
String b = new String("abc");
String c = new String("abc").intern();

所以a和c都指向常量池中的同一个字符串,而b指向堆中的String对象。但是三者的value属性都是指向同一个char数组的。如下图:

在这里插入图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值