阅读源码理解String对象的不变性

String的对象都有一个特性 ,就是不可变性,不可变是指String对象创建后,其值就不能再改变,代用String的任何方法修改字符串最后都会返回一个新的String对象,而对原String对象没有任何影响。下面通过解读源码和实例来进一步说明:

public class Test {
	public static void main(String[] args) {
		String s1="java";
		String s2="heima";
		String s11=s1.replace("a", "b");
		String s22=s2.replace("h", "H");
		//s1 s2的值不变
		System.out.println(s1);
		System.out.println(s2);
		//修改后返回的一个新String对象
		System.out.println(s11);
		System.out.println(s22);
		System.out.println(s1==s11);
		System.out.println(s2==s22);
	}
}

运行结果:

java
heima
jbvb
Heima
false
false

可以看到,通过replace方法并没能改变s1和s2的值,而且最终返回了一个新的String对象。

为什么不能直接修改String的变量呢?看一下String类的源码就一目了然了。

package java.lang;
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** 
     *	String字符串的本质是一个字符数组
     *	final限制了value引用是不可变的
     *	同时用private修饰,又没有提供setter和getter方法,
     *	最终决定了String类的不可变性
     *
     */
    private final char value[];
    //构造方法,创建一个长度为0的空字符数组
    public String() {
        this.value = new char[0];
    }
但是String类确实提供一些可以修改字符串的方法, concat,substring, replace, replaceAll等,可是从上面的例子中可以看出,最终并没有改变原字符串的值,这是为什么?

   public String substring(int beginIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        int subLen = value.length - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
    }
   public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);    }

    public String replace(char oldChar, char newChar) {
        if (oldChar != newChar) {
            int len = value.length;
            int i = -1;
            char[] val = value; /* avoid getfield opcode */

            while (++i < len) {
                if (val[i] == oldChar) {
                    break;
                }
            }
            if (i < len) {
                char buf[] = new char[len];
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];
                }
                while (i < len) {
                    char c = val[i];
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                return new String(buf, true);
            }
        }
        return this;
    }
不用管以上方法具体怎么实现的,只看最后的返回值,可以知道,都是用修改后的临时数组new一个新的String 返回给程序。

String类是不可变(final)的,对String类的任何改变,都是返回一个新的String类对象.这样的话把String类的引用传递给一个方法,该方法对String的任何改变,对原引用指向的对象没有任何影响。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值