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爱好者

Java基础笔记06

1118
来自专栏HappenLee的技术杂谈

C++雾中风景4:多态引出的困惑,对象的拷贝?

上面是两个继承关系的类定义。penguin(企鹅)类继承了bird类。在bird类之中fly()函数是一个virtual函数,它可以被penguin覆盖。我们看...

634
来自专栏向治洪

Java泛型和通配符那点事

泛型(Generic type 或者generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数...

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

C/C++ sizeof(上)

sizeof是C/C++中的一个操作符(operator),其作用是返回一个对象或者类型所占的内存字节数,使用频繁,有必须对其有个全面的了解。

561
来自专栏用户2442861的专栏

java泛型(一)、泛型的基本介绍和使用

http://blog.csdn.net/lonelyroamer/article/details/7864531

781
来自专栏编程

轻松学Python,一篇文章带你快速入门

Python基础01 Hello World! ? Python命令行 假设你已经安装好了Python, 那么在命令提示符输入: python 将直接进入pyt...

1857
来自专栏Kevin-ZhangCG

Java集合总结

1022
来自专栏康怀帅的专栏

PHP 面向对象 抽象类

使用 abstract 关键字申明抽象类和抽象方法。抽象类不能被实例化,只能被其他类继承。 abstract class A { // 抽象方法没有函数...

2656
来自专栏软件开发 -- 分享 互助 成长

为什么构造函数不能为虚函数

1、从使用角度         虚函数主要用于在信息不全的情况下,能使重载的函数得到对应的调用。构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀。所以...

1829
来自专栏liulun

Nim教程【七】

这是国内第一个关于Nim的系列教程 先说废话 很开心,在今天凌晨快一点多的时候拿到了 nim-lang.com;nim-lang.cn;nim-lang.net...

1875

扫码关注云+社区