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