• String到底能不能改变?


    不能改变的原因是什么?

    String底层是一个final修饰的char数组,private修饰的属性不能被外界访问,我们无法改变它,也无法影响String的值

    在这里插入图片描述
    初始化的String的地址不能改变,但是地址中的内容可以改变
    这个final修饰的char[] value 不是不可变,数组是引用类型,fianl修饰的引用类型不能指向其他引用,但是本身是可以修改的

    因此只要可以访问到String的value数组,就能达到修改String的目的

    可以改变的方式有哪些?

    1. 通过反射修改

    代码演示

    通过反射可以获取到String的私有属性value

    public class Test   {
        public static void main(String[] args) {
            String a = "hello";
            String b = "world";
            System.out.println(a+"的hashcode= "+a.hashCode());
            try {
                //反射获取string的私有属性value数组
                Field value = a.getClass().getDeclaredField("value");
                //设置value数组可以访问
                value.setAccessible(true);
                //获取value属性里面的值(内存地址)
                char[] temp = (char[])value.get(a);
                //通过temp的地址引用 找到真实String对象中的数组,修改数组内的元素
                value.set(a,new char[]{'x','x','x','x','x'});
                System.out.println(a+"的hashcode= "+a.hashCode());
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("a="+a+",b="+b);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述
    观察输出,字符串a已经通过反射拿到value数组修改过了

    还有一个问题,修改前后的 a 的hash相同。

    String的值修改了,它的hashCode为什么不变?

    hash值不等于地址,String的hash码是通过对每个字符进行一定规则累加得到的
    可以说一个String对象的hashCode()只会执行一次,因此它的值改变后,hash码还是原来的,为什么这么说?

    1. String中有一个hash属性,当第一次调用hashCode()时,hash为0,计算hash码,将hash码赋给hash,并返回hash码
    2. 当后面再次调用hashCode()时,返回的hash值其实时第一次计算出来的结果

    来看hashCode()的源码

    public int hashCode() {
    	//拿到String的hash
        int h = hash;
        //hash=0就去计算这个string的hashCode码
        if (h == 0 && value.length > 0) {
            char val[] = value;
    
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            //将hashCode结果赋给hash
            hash = h;
        }
        //hash不等于0,也就是这个String对象之前已经执行过hashCode()了,直接返回hash属性
        return h;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    总结:不能用hashCode()来判断是否是同一个字符串

    2. 通过SharedSecrets.getJavaLangAccess()来创建一个不安全的String

    代码演示

    public class TestString {
        public static void main(String[] args) {
            char[] chars = new char[]{'h','e','l','l','o'};
            String str = SharedSecrets.getJavaLangAccess().newStringUnsafe(chars);
    
            StringHolder holder = new StringHolder(str);
            System.out.println(holder.value);//hello
    
            for (int i = 0; i < chars.length; i++) {
                chars[i] = '?';
            }
            System.out.println(holder.value);//?????
    
            for (int i = 0; i < chars.length; i++) {
                chars[i] = '#';
            }
            System.out.println(holder.value);//#####
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述
    工作流程
    在这里插入图片描述

  • 相关阅读:
    通过IP地理位置阻止网络攻击
    贪吃蛇游戏制作
    Intel HAXM
    自定义注解实现多数据源+实现原理分析_02
    MongoDB的聚合笔记
    【Qt】对话框QDialog
    Estimator::relativePose
    MT4选网页版还是桌面版?anzo capital昂首资本分析优劣
    Fortify-解决中文乱码
    【BM2 链表内指定区间反转】
  • 原文地址:https://blog.csdn.net/lanleihhh/article/details/125429848