我们知道java的字符串类型String被设计成不可变的。那么我们还有办法改变它的值吗?

先来看一下,截取自jdk1.8.0_151的java.lang.String类的声明:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence 

String被设计成final类,即不可继承,同时实现了序列化等接口。

再来看一下,String的成员变量:

/** The value is used for character storage. */
private final char value[];

/** Cache the hash code for the string */
private int hash; // Default to 0

/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;

总共有三个成员变量,出来hash被设置为非final常量,其余全是常量。更重要的是value被设计为final,以维护String的不可变性。

我们利用反射来打破这种不可变性,看如下代码:

package com.modest.cainiao;

import java.lang.reflect.Field;

/**
 * 
 * @author heng.guo
 * @date 2018-07-28
 *
 */
public class StringImmutable {
    public static void main(String[] args) {
        String str = "ABCD";
        System.out.println("str = " + str);
        System.out.println("hashCode = " + str.hashCode());
        try {
            Field valueField = String.class.getDeclaredField("value");
            //value域是final private的,这里设置可访问
            valueField.setAccessible(true);
            char[] valueCharArr = (char[]) valueField.get(str);
            valueCharArr[0] = 'G';
            //此处输出第一组结果
            System.out.println("str = " + str);
            System.out.println("hashCode = " + str.hashCode());
            valueField.set(str, new char[] {'1', '2'});
          //此处输出第二组结果
            System.out.println("str = " + str);
            System.out.println("hashCode = " + str.hashCode());
        } catch (NoSuchFieldException | SecurityException 
                | IllegalArgumentException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

执行上述代码,我们观察到结果是这样的:

看起来,我们成功的修改了,str的值。

那如果我们把str的声明修改成这样呢?

final String str = "ABCD";

运行一下,看一下结果:

str没有改变。

那如果我们输出str的时候,调用它的toString()方法呢?即,输出时,改为以下方式:

System.out.println("str = " + str.toString());

运行结果如下:

 str的值看起来被修改了。那么我们看看String类中toString方法(截取自JDK1.8.0_151版本)的声明:

    /**
     * This object (which is already a string!) is itself returned.
     *
     * @return  the string itself.
     */
    public String toString() {
        return this;
    }

【备注】:在JDK1.9中,String的value被设计成byte[],不再是char[]了。

【问题】:加上final以后为什么值没有变,换成toString()之后为什么变了?


版权声明:本文为guohengcook原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/guohengcook/article/details/81264746