-
Notifications
You must be signed in to change notification settings - Fork 45.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
关于String类的实现的补充:Java 9 之后,String 类的实现改用 byte 数组存储字符串 #675
Comments
感谢补充! |
为什么使用byte字节而舍弃了char字符: 节省内存占用,byte占一个字节(8位),char占用2个字节(16),相较char节省一半的内存空间。节省gc压力。 |
String 可以存放汉字,String的 []方法返回值还是char,估计是两个byte实现的, |
这是why? |
这里的被final修饰的变量指向的是一个数组,被final修饰的不可更改指的是 value变量存储的值也就是字符数组的地址不能再更改,即不能再将一个新的对象赋值给value(value = new char[3],这样编译是会报错的).但是value指向的数组里头的元素值还是可以修改的 |
那为什么String对象是不可变的呢?String对象字符数组不是可以通过下标更改字符串的某个元素么。。。 |
虽然我们可以使用反射跳过安全检查,设置字符数组的值,改变值后,打印出的字符串确实是改变了,但是我们通过对象的hashCode方法查看hash值发现,hashCode并没有随着字符数组被修改而改变.根据hash值的计算规则我们知道,如果一个对象的被修改了,那么它的hash值肯定也会跟着变化,我理解的String不可变指的是这个.虽然我们可以通过反射来改变字符数组的值而在显示上改变字符串的值,实际上该字符串的hash值并没有改变.在实际中不建议这样做. public static void main(String [] args) throws IllegalAccessException, InstantiationException {
Class clazz = String.class;
String strObj = "12345";
Field [] fields = clazz.getDeclaredFields();
char [] obj = null;
System.out.println("before change hashcode is "+ strObj.hashCode());
// before change hashcode is 46792755
for (int i = 0; i < fields.length; i++) {
if(fields[i].getName().equals("value")) {
fields[i].setAccessible(true);
obj = (char[]) fields[i].get(strObj);
obj[0] = 'c';
}
}
System.out.println(strObj);
// c2345
System.out.println("after change new hashCode is "+strObj.hashCode());
// after change new hashCode is 46792755 与之前相同
System.out.println("12345".hashCode()); // 46792755
System.out.println("c2345".hashCode()); // 92968805
} 上面的代码只能解释一种情况,经测试又发现了新的情况,我也不知道为什么出现这样的情况,希望有大佬释疑一下?谢谢 public static void main(String [] args) throws IllegalAccessException, InstantiationException {
Class clazz = String.class;
String strObj = new String("12345");
Field [] fields = clazz.getDeclaredFields();
char [] obj = null;
Field hash = null;
System.out.println("before change hashcode is "+ strObj.hashCode());
// before change hashcode is 46792755
for (int i = 0; i < fields.length; i++) {
if(fields[i].getName().equals("value")) {
fields[i].setAccessible(true);
obj = (char[]) fields[i].get(strObj);
obj[0] = 'c';
}
}
System.out.println(strObj);
// c2345
System.out.println("after change new hashCode is "+strObj.hashCode());
// after change new hashCode is 46792755 与之前相同
System.out.println("12345".hashCode()); // 92968805
System.out.println("c2345".hashCode()); // 92968805
} |
这个问题有意思,:joy::joy:
所有后面代码在修改这个数组的是否把常量池里的string对象数组给改了
这两行代码打印hash的时候取的是常量池里面的对象所以计算结果实际就是“c2345"的hash
|
涉及到hash的初始化和缓存 new string和直接字面量 两者strObj 不一样
|
因为理想情况下 String 是不可变的, hashCode 按理说是不会发生改变的,因此在设计的时候是这样设计的:在新建 String 对象的时候就会计算一次 hashCode 的值,并保存在 String 类的成员变量 hash 中,当你调用 hashCode() 方法时,仅仅是返回了 hash 值,而不是重新计算一次该字符串对应的 hashCode。
|
|
在 Java 9 之后,String 类的实现改用 byte 数组存储字符串
private final byte[] value;
The text was updated successfully, but these errors were encountered: