V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
huf
V2EX  ›  Java

Java 字符串如何理解

  •  
  •   huf · 2022-01-22 21:54:00 +08:00 · 1940 次点击
    这是一个创建于 796 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在 JDK 中 String 的 String 参数的构造方法里面有这样的说明

    初始化一个新创建的 String 对象,使其表示与参数相同的字符序列;换句话说,新创建的字符串是参数字符串的副本。除非需要原始的显式副本,否则不需要使用此构造函数,因为字符串是不可变的。

    如图: 文档截图

    怎么理解其中的“新创建的字符串是参数字符串的副本。”这句话

    我做了如下实验 代码:

    import java.lang.reflect.Field;
    
    public class StringTest {
        public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
            String strabc1 = "abc";
    
            Class<? extends String> aClass = strabc1.getClass();
            Field abcValue = aClass.getDeclaredField("value");
            abcValue.setAccessible(true);
            byte[] chars = (byte[]) abcValue.get(strabc1);
            chars[0] = 'd';
            chars[1] = 'e';
            chars[2] = 'f';
    
            String newStrAbc1 = new String("abc");
            String newStrAbc2 = new String("abc");
            System.out.println(strabc1);
            System.out.println("abc".equals("def"));
            System.out.println(newStrAbc1.equals("def"));
            System.out.println(newStrAbc1 == newStrAbc2);
            System.out.println(newStrAbc1.equals(newStrAbc2));
        }
    }
    

    运行结果截图: 运行结果截图

    如图改变了“abc”的值之后字符串常量池中“abc”实际的值已经改变为“def”所以用“abc”equals“def”的时候返回 true ,我不理解的是文档中说的“副本”具体是怎么个副本法? 21 行代码输出的是 true 证明 new String 的这种方式创建出来的字符串也受字符串常量的影响,new String 创建出来的字符串使用==判断输出 false 比如如图 23 行代码输出的是 false ,按网上所说是地址不一样,地址不一样,但是又受字符串常量池的影响,我就疑惑这个文档中的“副本”是指什么概念?

    第 1 条附言  ·  2022-01-22 22:43:21 +08:00
    感谢各位,感谢 @chendy 提醒,用浅克隆可以很好的来理解,我也实验了一下 new String 出来的 String 对象里面的 value 数组是和常量方式 String 的 value 的数组 HashCode 值是一样的,是我愚钝了纠结了好久。
    8 条回复    2022-01-23 03:27:53 +08:00
    chendy
        1
    chendy  
       2022-01-22 22:02:32 +08:00   ❤️ 1
    除非你 new String("abc"),否则所有的 "abc" 都是同一个对象
    所以把 "abc" 的内容修改成 “def" 之后 ,所有的 "abc" 都变成了 "def"
    所以 new String("abc") 得到的也是 "def"
    huf
        2
    huf  
    OP
       2022-01-22 22:13:09 +08:00
    @chendy 你好,我的意思是文档中的“新创建的字符串是参数字符串的副本”这句话怎么理解,既然是副本为什么会受字符串常量的影响?那都是使用的字符串常量为什么使用==符号判断又会是 false
    chendy
        3
    chendy  
       2022-01-22 22:17:07 +08:00
    @huf 分清楚”内容相同“和”是同一个“就行了
    likeunix
        4
    likeunix  
       2022-01-22 22:18:47 +08:00 via Android   ❤️ 1
    它说的那个副本是浅克隆,你说的副本是深克隆。它虽然产生了副本,但是都还是指向同一个存储字符的内存地址,所以你改了一个就都变了。
    eason1874
        5
    eason1874  
       2022-01-22 22:19:32 +08:00
    这里的 copy 翻译成拷贝会好理解很多吧

    new String("abc") 是拷贝 abc 的值,而非引用,所以是拷贝了 abc 的值 def 传入一个新的地址

    所以使用 == 比较引用地址的时候 false ,使用 equals() 比较值的时候则为 true
    huf
        6
    huf  
    OP
       2022-01-22 22:23:01 +08:00
    @chendy 其实就是不太理解这个“副本”是具体怎么个副本法,如果只是单纯的”内容相同“那么修改字符串常量池中字符串的内容不应该影响 new String 这种“副本”方式创建的字符串的内容,如果说是”同一个“那么使用==操作符应该是 true 才对,所以也很好奇他这个“副本”是怎么个”副本“法
    huf
        7
    huf  
    OP
       2022-01-22 22:26:23 +08:00
    @likeunix 谢谢你,好像用浅克隆可以来理解这个意思
    iseki
        8
    iseki  
       2022-01-23 03:27:53 +08:00
    换个角度理解,文档的含义是创建 String 对象的副本,至于对象里面的那个 array 属于不公开的实现细节,文档并没有保证会创建那个 array 的副本。而你用反射进行修改很显然是不正常的行为,那么出现问题就是很正常的咯~~~
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1066 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 19:07 · PVG 03:07 · LAX 12:07 · JFK 15:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.