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 条评论
登录 后参与评论

相关文章

来自专栏编程

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

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

2009
来自专栏Python数据科学

Python爬虫之快速入门正则表达式

当完成了网页html的download之后,下一步当然是从网页中解析我们想要的数据了。那如何解析这些网页呢?Python中有许多种操作简单且高效的工具可以协助我...

1253
来自专栏C/C++基础

认识初始化

初始化是编码过程中的重要操作,往往由于被忽略,导致使用未初始化的变量(或内存区域),将程序置于不确定的状态,产生各种bug,严重影响的程序的健壮性。正确地理解和...

731
来自专栏程序生活

Python itertools的使用简介无限迭代器chain方法

用*放在一个可迭代对象前面可以将对象拆分成多个单元素,比如first=[['1','2','3','4','4'],['2','4','2']],如果把*放在f...

761
来自专栏思考的代码世界

Python编程从入门到实践之列表|第1天

列表由一系列按特定顺序排列的元素组成。可以创建包含字母表中所有字母、数字0~9或 所有家庭成员姓名的列表;也可以将任何东西加入列表中,其中的元素之间可以没有任何...

3615
来自专栏blackheart的专栏

[C#6] 3-null 条件运算符

0. 目录 C#6 新增特性目录 1. 老版本的代码 1 namespace csharp6 2 { 3 internal class Perso...

22210
来自专栏Java编程

Java泛型详解

Java泛型(generics)是JDK 5中引入的一个新特性,允许在定义类和接口的时候使用类型参数(type parameter)。声明的类型参数在使用时用具...

7600
来自专栏nummy

python operator模块学习

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

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

Java进阶01 String类

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

882
来自专栏决胜机器学习

《Redis设计与实现》读书笔记(一)——简单动态字符串(SDS)

《Redis设计与实现》读书笔记(一) ——简单动态字符串(SDS) (原创内容,转载请注明来源,谢谢) 前言:《Redis设计与实现》,是一本分析redis...

4375

扫码关注云+社区

领取腾讯云代金券