Java漫谈9
上次聊String的时候聊到了String为什么可以在不new的情况下创建,说实话,这个问题我也没有答案,直到看到了这篇帖子,才敢说知道了为什么。
《Java String 两种不同的赋值方案比较》
http://blog.163.com/woshihezhonghua@126/blog/static/1271436362012101214031911/
简单来说,就是因为java的编译器会自动给你加上。由此,我想到两点:
第一是,java中的那些基本数据类型,会不会也是由编译器自动加上new这个关键字的。搜了一下必应,没搜到什么有效的答案。
第二是,String是引用数据类型,那既然是引用数据类型,为什么不像其它的引用数据类型一样,直接用new这个关键字来创建对象,而非要用弄出一个类似于基本数据类型的创建对象的方式。按照存在即合理的逻辑,那我们就试着从这二者创建流程的不同这个角度去看看能不能得出结论。
先说一下一个概念,栈内存和堆内存。你可以把它们看做在内存中储存运算数据的两个仓库,一个储存的是数据的变量名,相当于数据的别名,或者是数据的标签。另一个是储存数据本身,比如字符数组“Hello World”。另外还有一个常量池的概念,它是不同于堆栈的另一个储存区域,可以可以把它当做是一个常用工具存放仓库。
我们先来看看用new这个关键字,它的生成过程是什么样的:
String str1 = new String("hello");
首先,系统会先在常量池中寻找有没有“hello”,如果没有的话,就先在常量池中创建“hello”对象,然后再在堆内存中创建“hello”对象(也就是把“hello”放入堆内存),然后再把它的地址值传给栈内存中的str1。如果常量池中有“hello”对象了,那么在常量池中不会再创建,但在堆内存中会再创建的。如果常量池中的“hello”长时间没有被引用,java的垃圾回收器就会自动将它回收,释放“hello”对象所占用的空间。对于堆内存中的“hello”对象也是如此。
其次再来看看直接赋值的方式,流程是怎么样的:
String str2 = "hello";
系统会先在常量池中寻找有没有“hello”对象,如果有的话就直接使用,没有的话就在常量池中新建一个,也叫入池。而堆栈当中则不需要开辟新空间。
如此一来,如果下次还有String的对象也用直接赋值的方式定义为“hello”,既不需要再次在常量池中创建,又不需要在堆栈中创建,直接指向这个堆栈中的“hello”对象即可。
再进一步,也就是说用直接赋值的方式定义两个String类型的对象,用双等号“==”判断的话,结果为true。
这里补充说一下,在java中,双等号是用来判断相等的,在String中它判断的是对象的地址是否相等,若要判断String的值是否相等,要用equals方法。
以此再进一步,要是用new的方式和直接赋值的方式分别创建的话,也就是用str1与str2比较,结果为false。
但如果我就是想要用让str1与str2相等,该怎么做呢。因为str1对对象的引用是用的是对象在堆内存中的地址,如果能把这个引用的地址变为“hello”对象在常量池中的对象,这样双等号判断的时候就会为true了。而java中也提供了这样的方法 —— intern(),也叫“入池方法”,具体用法如下:
String str1 = new String("hello").intern();
所以总的来说,用直接赋值的方法效率会比较高。
最后,我想说说我看懂了这种设计思想之后的感受。在计算机中,仍然是十分看中效率的。尤其在看中效率的过程中,可能会衍化出一些我们看似差不多,效果也差不多的相似方法或属性。这些东西一开始我只是会用,但说不上原因,在逐渐的模仿之中逐渐地形成了习惯用法,而新入门的人又会顺着这个方式一轮一轮,反复循环。如果在用熟了,形成习惯了之后,我们能去进一步地了解一下原理,也许就能使我们对代码的具体使用场景理解加深,然后再用到编程中,做到合适的代码放到合适的地方,最终能在编程效率和程序执行效率上得到一些提升。
今天我与你聊了String的直接赋值的创建方式,希望对你使用String有帮助,我们下回见。
清单
- 总的来说,用直接赋值的方式效率比较高。
- 用new的方式创建String对象后,可以用intern()方法将其放入常量池中。
- 在String中,双等号是判断对象的地址是否相等,用equals才是判断对象的值是否相等。
- 性能测试必备监控技能linux篇14
- JMeter函数和变量11
- JMeter监听器10
- JMeter处理器09
- 保存带有emoji的文本报错解决方案
- Python:set集合、深浅拷贝与函数
- Python:numpy总结(4)
- Python: numpy总结(2)
- class 类—老司机的必修课 | 统计师的Python日记 第11课
- Python:matplotlib
- Python: matplotlib安装
- Java后端实现图片压缩技术(赞赏功能已开通,欢迎测试,噗~!)
- 我是如何得知10W+的访问量多来自工作日的 | 塔秘
- 使用百度UMeditor富文本编辑器,修改自定义图片上传,修改源码
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Greenplum 列存表(AO表)的膨胀和垃圾检查与空间收缩
- 数据结构系列:图文详解冒泡排序 & 优化
- Set 数据结构
- (数据科学学习手札97)掌握pandas中的transform
- tcp socket的发送与接收缓冲区
- Node.js模块化开发
- GO语言之旅:数组、切片
- 系统模块
- 深入 TypeScript 中的子类型,进阶 Vue3 源码前必须搞懂的。
- 第三方模块
- package.json文件的作用
- C语言的原子操作
- 【Linux】tmux命令使用教程
- 【Android 音视频开发打怪升级:FFmpeg音视频编解码篇】七、Android FFmpeg 视频编码
- 2020已经过去五分之四了,你确定还不来了解一下JS的rAF?