前言

这两天在看Java面试相关的一些问题,很偶然也很幸运的看到了下面这篇文章。
https://www./article/105448.htm
这篇文章的作者有一系列关于Java深入学习的文章,很值得一看,个人觉得非常好,很有收获。
起因
正如我们所理解的,通过
String hello = "Hello World!";
和
String xx = new String("Hello World!");
得到的字符串对象是不一样的,new方式是在堆空间中创建的,而直接的字符串则是先被放到常量池中。如果有新的与之一样的对象被创建,则直接让这个新对象引用常量池中的这个地址即可。
这样的好处就是可以最大限度的节省内存空间。
而使用new方式创建的则就不一样了,只要是用了new创建字符串,就会在堆空间中开辟出一块内存,然后返回这个内存地址的引用。所以这样创建的对象,即使内容一致,也不会是指向同一个内存地址。
下面用几个简单的代码做下测试。
/** *字符串中对于内容和地址的判定可以用下面两种方式,但侧重点不一样。 */ equals // 判断 两个字符串的内容是否一致 == // 判断两个字符串的内存地址是否一致
且看下面的代码:
public static void simple() {
String s1 = "Hello World!";
String s2 = "Hello World!";
String s3 = new String("Hello World!");
String s4 = new String("Hello World!");
// 下面开始比较引用和内容的比较
System.out.println("字符串赋值方式:");
System.out.println(s1==s2);
System.out.println(s1.equals(s2));
System.out.println("\n字符串赋值方式和new方式:");
System.out.println(s1==s3);
System.out.println(s1.equals(s3));
System.out.println("\nnew 方式:");
System.out.println(s3==s4);
System.out.println(s3.equals(s4));
}
得到的结果如下:
字符串赋值方式: true true 字符串赋值方式和new方式: false true new 方式: false true
结果却是和我们所说的那样。
深入源码
不出所料,String确实是“不可变的”,每次改变底层其实都是创建了一个心的字符串对象,然后赋予了新值。
为什么会这样呢?我们也许可以在源码中找到真相。
哦,原来Java对于String类只是维护了一个final类型的字符数组啊。怪不得赋值之后就不能改变了呢。
但是也许你会有疑问,咦,不对啊,“我经常使用String的什么replace方法改变字符串的内容啊。你这则么解释呢?”
其实答案还是那样,它真的没变,我们并没有看到事情的真相,相信看完下面的源码,你就明白了。
/**
* Returns a string resulting from replacing all occurrences of
* {@code oldChar} in this string with {@code newChar}.
* <p>
* If the character {@code oldChar} does not occur in the
* character sequence represented by this {@code String} object,
* then a reference to this {@code String} object is returned.
* Otherwise, a {@code String} object is returned that
* represents a character sequence identical to the character sequence
* represented by this {@code String} object, except that every
* occurrence of {@code oldChar} is replaced by an occurrence
* of {@code newChar}.
* <p>
* Examples:
* <blockquote><pre>
* "mesquite in your cellar".replace('e', 'o')
* returns "mosquito in your collar"
* "the war of baronets".replace('r', 'y')
* returns "the way of bayonets"
* "sparring with a purple porpoise".replace('p', 't')
* returns "starring with a turtle tortoise"
* "JonL".replace('q', 'x') returns "JonL" (no change)
* </pre></blockquote>
*
* @param oldChar the old character.
* @param newChar the new character.
* @return a string derived from this string by replacing every
* occurrence of {@code oldChar} with {@code newChar}.
*/
public String replace(char oldChar, char newChar) {
if (oldChar != newChar) {
int len = value.length;
int i = -1;
char[] val = value; /* avoid getfield opcode */
while (++i < len) {
if (val[i] == oldChar) {
break;
}
}
if (i < len) {
char buf[] = new char[len];
for (int j = 0; j < i; j++) {
buf[j] = val[j];
}
while (i < len) {
char c = val[i];
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
return new String(buf, true);
}
}
return this;
}
源码中很明确的使用了
new String(buf, true);
的方式返回给调用者新对象了。
真的不可变吗?
读到上面的内容,其实基本上已经够了。但是了解一下更深层次的内容,相信对我们以后编程来说会更好。
源码中清楚的使用char[] value来盛装外界的字符串数据。也就是说字符串对象的不可变的特性,其实是源自value数组的final特性。
那么我们可以这么想,我们不改变String的内容,而是转过头来改变value数组的内容(可以通过反射的方式来修改String对象中的private属性的value),结果会怎样呢?
答案是真的会变哦。
可以先看下下面的代码
private static void deep() throws NoSuchFieldException, IllegalAccessException {
String hello = "Hello World!";
String xx = new String("Hello World!");
String yy = "Hello World!";
/**
* 判断字符串是否相等,默认以内存引用为标准
*/
System.out.println(hello == xx);
System.out.println(hello == yy);
System.out.println(xx == yy);
// 查看hello, xx, yy 三者所指向的value数组的真实位置
Field hello_field = hello.getClass().getDeclaredField("value");
hello_field.setAccessible(true);
char[] hello_value = (char[]) hello_field.get(hello);
System.out.println( hello_field.get(hello));
Field xx_field = xx.getClass().getDeclaredField("value");
xx_field.setAccessible(true);
char[] xx_value = (char[]) xx_field.get(xx);
System.out.println(xx_field.get(xx));
Field yy_field = yy.getClass().getDeclaredField("value");
yy_field.setAccessible(true);
char[] yy_value = (char[]) yy_field.get(yy);
System.out.println(yy_field.get(yy));
/**
* 经过反射获取到这三个字符串对象的最底层的引用数组value,发现如果一开始内容一致的话,java底层会将创建的字符串对象指向同一个字符数组
*
*/
// 通过反射修改字符串引用的value数组
Field field = hello.getClass().getDeclaredField("value");
field.setAccessible(true);
char[] value = (char[]) field.get(hello);
System.out.println(value);
value[5] = '^';
System.out.println(value);
// 验证xx是否被改变
System.out.println(xx);
}
结果呢?
false true false [C@6d06d69c [C@6d06d69c [C@6d06d69c Hello World! Hello^World! Hello^World!
真的改变了。
而我们也可以发现,hello,xx, yy最终都指向了内存中的同一个value字符数组。这也说明了Java在底层做了足够强的优化处理。
当创建了一个字符串对象时,底层会对应一个盛装了相应内容的字符数组;此时如果又来了一个同样的字符串,对于value数组直接获取刚才的那个引用即可。(相信我们都知道,在Java中数组其实也是一个对象类型的数据,这样既不难理解了)。
不管是字符串直接引用方式,还是new一个新的字符串的方式,结果都是一样的。它们内部的字符数组都会指向内存中同一个“对象”(value字符数组)。
总结
稍微有点乱,但是从这点我们也可以看出String的不可变性其实仍旧是对外界而言的。在最底层,Java把这一切都给透明化了。我们只需要知道String对象有这点特性,就够了。
其他的,日常应用来说,还是按照String对象不可变来使用即可。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
# java
# String
# 可变性的分析
# Sting
# 不可变吗?java
# String可变
# JAVA不可变类(immutable)机制与String的不可变性(推荐)
# 这篇文章
# 池中
# 都是
# 最底层
# 几个
# 有一
# 改变了
# 是在
# 你就
# 却是
# 你会
# 则是
# 两种
# 可以用
# 很有
# 只需
# 其他的
# 会在
# 是从
# 我们可以
相关文章:
如何用手机制作网站和网页,手机移动端的网站能制作成中英双语的吗?
如何用PHP快速搭建高效网站?分步指南
济南网站建设制作公司,室内设计网站一般都有哪些功能?
如何实现建站之星域名转发设置?
如何在万网ECS上快速搭建专属网站?
html制作网站的步骤有哪些,iapp如何添加网页?
网站制作大概多少钱一个,做一个平台网站大概多少钱?
微信网站制作公司有哪些,民生银行办理公司开户怎么在微信网页上查询进度?
如何注册花生壳免费域名并搭建个人网站?
香港服务器网站生成指南:免费资源整合与高速稳定配置方案
定制建站价位费用解析与套餐推荐全攻略
如何在阿里云高效完成企业建站全流程?
如何配置WinSCP新建站点的密钥验证步骤?
宁波自助建站系统如何快速打造专业企业网站?
,想在网上投简历,哪几个网站比较好?
宠物网站制作html代码,有没有专门介绍宠物如何养的网站啊?
制作网站的网址是什么,请问后缀为.com和.com.cn还有.cn的这三种网站是分别是什么类型的网站?
详解jQuery中基本的动画方法
如何在云虚拟主机上快速搭建个人网站?
宝塔面板创建网站无法访问?如何快速排查修复?
建站主机选购指南:核心配置优化与品牌推荐方案
小视频制作网站有哪些,有什么看国内小视频的网站,求推荐?
装修招标网站设计制作流程,装修招标流程?
厦门模型网站设计制作公司,厦门航空飞机模型掉色怎么办?
如何在万网自助建站中设置域名及备案?
如何在腾讯云服务器快速搭建个人网站?
标准网站视频模板制作软件,现在有哪个网站的视频编辑素材最齐全的,背景音乐、音效等?
linux top下的 minerd 木马清除方法
如何高效完成自助建站业务培训?
猪八戒网站制作视频,开发一个猪八戒网站,大约需要多少?或者自己请程序员,需要什么程序员,多少程序员能完成?
如何在香港免费服务器上快速搭建网站?
建站主机服务器选购指南:轻量应用与VPS配置解析
建站之星北京办公室:智能建站系统与小程序生成方案解析
网站建设设计制作营销公司南阳,如何策划设计和建设网站?
香港服务器建站指南:外贸独立站搭建与跨境电商配置流程
建站之星备案是否影响网站上线时间?
如何用美橙互联一键搭建多站合一网站?
招贴海报怎么做,什么是海报招贴?
如何零基础在云服务器搭建WordPress站点?
,购物网站怎么盈利呢?
在线制作视频的网站有哪些,电脑如何制作视频短片?
如何选择长沙网站建站模板?H5响应式与品牌定制哪个更优?
Python多线程使用规范_线程安全解析【教程】
成都网站制作价格表,现在成都广电的单独网络宽带有多少的,资费是什么情况呢?
如何通过IIS搭建网站并配置访问权限?
如何制作公司的网站链接,公司想做一个网站,一般需要花多少钱?
手机网站制作与建设方案,手机网站如何建设?
高端建站三要素:定制模板、企业官网与响应式设计优化
英语简历制作免费网站推荐,如何将简历翻译成英文?
广州网站制作公司哪家好一点,广州欧莱雅百库网络科技有限公司官网?
*请认真填写需求信息,我们会在24小时内与您取得联系。