如何改变String类的值,保证地址不变!

一、String是一个不可变类

  我们都知道String是一个不可变类,因为它的源码内部维护着一个final修饰的char数组,final修饰的变量不可以被改变,修饰的方法不可以被重写,修饰的类不可以被继承:(简要源码)

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

也就是说:String对象一旦创建,就不可改变。拼接、截取或者重新赋值都是在重新建对象。

做一下代码演示:

/**
 * @Author 程Sir
 * @Version 2020年3月26日上午11:20:51
 * @description 描述:字符串不可以被改变
 */
public class Demo {

    public static void main(String[] args) throws IOException {
        String str = "不变的字符串";
        System.out.println("1. " + str +" : " + str.hashCode());
        
        str = str.substring(2);
        System.out.println("3. " + str +" : " + str.hashCode());
        
        str = str+1;
        System.out.println("2. " + str +" : " + str.hashCode());
    }

}

输出的结果是:

  1. 不变的字符串 : 83361354
  3. 的字符串 : 927327327
  2. 的字符串1 : -1317623886

通过演示表明:hashcode值每次都是不一样的。说明操作的不是同一对象,再次过程中有新的对象被创建。

二、应用Java中的反射机制

  我们学习了反射机制,了解到:反射是在运行期能够对类的属性、方法进行操作。即:运行期绑定。那么我们是不是可以在String运行期对它的值进行一个完美操作了,答案是肯定的,完全可以的,看以下代码:

/**
 * @Author 程Sir
 * @Version 2020年3月26日上午11:20:51
 * @description 描述:字符串不可以被改变
 */
public class Demo {

    public static void main(String[] args) throws IOException {
        String str = "不变的字符串";
        System.out.println("1. " + str +" : " + str.hashCode());
        
        try {
            //反射通过属性拿到值,Sting类的属性char数组的属性名为:value
            Field field = str.getClass().getDeclaredField("value");
            //设置该属性为可操作
            field.setAccessible(true);
            //改变该属性的值:改变char数组
            field.set(str, new char[]{'程','s','i','r'});
            
            System.out.println("2. " + str+" : " + str.hashCode());
                                        
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
输出的结果是:

  1. 不变的字符串 : 83361354
  2. 程sir : 83361354

从演示结果中,我们发现,字符串str的hashcode值两次相等,并没有发生改变,说明是同一对象,但前后的值(内容)完全是发生了改变。即达到了我们的目的:String类的值是可以通过Java的反射机制进行改变的。

三、总结

  最后,我们做一个总结:

  String类是用final关键字修饰的,那值就是不可以改变,值不可以改变,导向到结果是这个值的引用地址在内存中是不可被改变。再String类的本质是内部维护这一个char类型的数组,明确这点后,我们既可以通过Java反射机制的特性,在运行期对其内部的char数组内容进行操作,从而达到改变String类内容的目的。

 

posted on 2020-03-26 11:38  零度的脚步  阅读(1960)  评论(0编辑  收藏  举报

导航