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有帮助,我们下回见。

清单

  1. 总的来说,用直接赋值的方式效率比较高。
  2. 用new的方式创建String对象后,可以用intern()方法将其放入常量池中。
  3. 在String中,双等号是判断对象的地址是否相等,用equals才是判断对象的值是否相等。

原文发布于微信公众号 - 怀英的自我修炼(hydzwxl)

原文发表时间:2017-11-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Modeng的专栏

Javascript数组系列五之增删改和强大的 splice()

今天是我们介绍数组系列文章的第五篇,也是我们数组系列的最后一篇文章,只是数据系列的结束,所以大家不用担心,我们会持续的更新干货文章。

1182
来自专栏编程

Python面向对象4:属性、成员修饰符

1、属性: +@property的函数,具有属性,可以直接取值。属性具有方法的写作形式,同时具有字段的访问形式,访问时不需要加()。 案例1:不加属性的调用普通...

1829
来自专栏锦小年的博客

python学习笔记4.2-python高级之迭代器

迭代是Python中最强有力的特性之一,同时对编程人员来说,也是最难理解的一种用法。其实从高层次来看,迭代就是一种处理序列中元素的方式。通过自定义迭代对象可以...

20510
来自专栏互联网技术栈

JVM解读-方法区

方法区,Method Area, 对于习惯在HotSpot虚拟机上开发和部署程序的开发者来说,很多人愿意把方法区称为“永久代”(Permanent Genera...

1484
来自专栏CDA数据分析师

陷阱!python参数默认值

在stackoverflow上看到这样一个程序: class demo_list: def __init__(self, l=[]): ...

2078
来自专栏微信公众号:Java团长

Java进阶01 String类

之前的Java基础系列中讨论了Java最核心的概念,特别是面向对象的基础。在Java进阶中,我将对Java基础进行补充,并转向应用层面。

802
来自专栏黄Java的地盘

正则表达式之进阶篇

本文主要通过介绍正则表达式中的一些进阶内容,让读者了解正则表达式在日常使用中用到的比较少但是又比较重要的一部分内容,从而让大家对正则表达式有一个更加深刻的认识。

1193
来自专栏猿人谷

Java初学者需掌握的30个概念

基本概念:       1.OOP中唯一关心的是对象的接口是什么,就像计算机的销售商她不管电源内部结构 是怎样的,他只关系能否给你提供电就行了,也就是只要知道c...

16510
来自专栏nummy

python operator模块学习

operator模块是python中内置的操作符函数接口,它定义了一些算术和比较内置操作的函数。operator模块是用c实现的,所以执行速度比python代码...

692
来自专栏Python爬虫实战

Python数据类型之字典(上)

之前系列文章介绍了Python简单数据类型和序列数据类型,本文来学习一种新的映射数据类型:字典。

811

扫码关注云+社区