Java 字符串如何理解

2022-01-22 21:54:00 +08:00
 huf

在 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 ,按网上所说是地址不一样,地址不一样,但是又受字符串常量池的影响,我就疑惑这个文档中的“副本”是指什么概念?

1961 次点击
所在节点    Java
8 条回复
chendy
2022-01-22 22:02:32 +08:00
除非你 new String("abc"),否则所有的 "abc" 都是同一个对象
所以把 "abc" 的内容修改成 “def" 之后 ,所有的 "abc" 都变成了 "def"
所以 new String("abc") 得到的也是 "def"
huf
2022-01-22 22:13:09 +08:00
@chendy 你好,我的意思是文档中的“新创建的字符串是参数字符串的副本”这句话怎么理解,既然是副本为什么会受字符串常量的影响?那都是使用的字符串常量为什么使用==符号判断又会是 false
chendy
2022-01-22 22:17:07 +08:00
@huf 分清楚”内容相同“和”是同一个“就行了
likeunix
2022-01-22 22:18:47 +08:00
它说的那个副本是浅克隆,你说的副本是深克隆。它虽然产生了副本,但是都还是指向同一个存储字符的内存地址,所以你改了一个就都变了。
eason1874
2022-01-22 22:19:32 +08:00
这里的 copy 翻译成拷贝会好理解很多吧

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

所以使用 == 比较引用地址的时候 false ,使用 equals() 比较值的时候则为 true
huf
2022-01-22 22:23:01 +08:00
@chendy 其实就是不太理解这个“副本”是具体怎么个副本法,如果只是单纯的”内容相同“那么修改字符串常量池中字符串的内容不应该影响 new String 这种“副本”方式创建的字符串的内容,如果说是”同一个“那么使用==操作符应该是 true 才对,所以也很好奇他这个“副本”是怎么个”副本“法
huf
2022-01-22 22:26:23 +08:00
@likeunix 谢谢你,好像用浅克隆可以来理解这个意思
iseki
2022-01-23 03:27:53 +08:00
换个角度理解,文档的含义是创建 String 对象的副本,至于对象里面的那个 array 属于不公开的实现细节,文档并没有保证会创建那个 array 的副本。而你用反射进行修改很显然是不正常的行为,那么出现问题就是很正常的咯~~~

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/829984

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX