
在 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 chendy 除非你 new String("abc"),否则所有的 "abc" 都是同一个对象 所以把 "abc" 的内容修改成 “def" 之后 ,所有的 "abc" 都变成了 "def" 所以 new String("abc") 得到的也是 "def" |
2 huf OP @chendy 你好,我的意思是文档中的“新创建的字符串是参数字符串的副本”这句话怎么理解,既然是副本为什么会受字符串常量的影响?那都是使用的字符串常量为什么使用==符号判断又会是 false |
4 likeunix Jan 22, 2022 via Android 它说的那个副本是浅克隆,你说的副本是深克隆。它虽然产生了副本,但是都还是指向同一个存储字符的内存地址,所以你改了一个就都变了。 |
5 eason1874 Jan 22, 2022 这里的 copy 翻译成拷贝会好理解很多吧 new String("abc") 是拷贝 abc 的值,而非引用,所以是拷贝了 abc 的值 def 传入一个新的地址 所以使用 == 比较引用地址的时候 false ,使用 equals() 比较值的时候则为 true |
6 huf OP @chendy 其实就是不太理解这个“副本”是具体怎么个副本法,如果只是单纯的”内容相同“那么修改字符串常量池中字符串的内容不应该影响 new String 这种“副本”方式创建的字符串的内容,如果说是”同一个“那么使用==操作符应该是 true 才对,所以也很好奇他这个“副本”是怎么个”副本“法 |
8 iseki Jan 23, 2022 换个角度理解,文档的含义是创建 String 对象的副本,至于对象里面的那个 array 属于不公开的实现细节,文档并没有保证会创建那个 array 的副本。而你用反射进行修改很显然是不正常的行为,那么出现问题就是很正常的咯~~~ |