您的位置:首页 > 编程语言 > Java开发

Java为什么需要保留基本数据类型

2014-07-27 18:52 501 查看
基本数据类型对以数值计算为主的应用程序来说是必不可少的。自从1996年Java发布以来,基本数据类型就是Java语言的一部分。John Moore通过对使用基本类型和不使用基本类型做java基准测试给Java中为什么要保留基本数据类型做了一个很有力的说明。然后,他还在特定类型的应用中把Java和Scala、C++和JavaScript的性能做了对比。在这些应用中,使用基本数据类型应用性能会有很显著的不同。问:影响买房最重要的三个因素是什么?
答:位置!位置!还是位置!!这是个很古老但却经常被提及的谚语。意思是,当购买房产的时候,位置因素是绝对的主导因素。与此类似,考虑在Java中使用基本数据类型的3个最重要的因素,那就是性能!性能!还是性能!!房产与基本数据类型有两个不同之处。首先,位置主导几乎适用于所有买房的情况。但是使用基本类型带来的性能提升,对不同类型的应用程序来大不相同。其次,尽管其他的因素与位置相比在买房时都显得不太重要,但是也是应该被考虑的因素。而使用基本数据类型的原因却只有一个――那就是性能,并且只适用于那些使用后能提升性能的应用。基本数据类型对大多数业务相关或网络应用程序没有太大的用处,这些应用一般是采用客户端/服务器模式,后端有数据库。然而,使用基本数据类型对那种以数值计算为主的应用提升性能有很大好处。在Java语言中包含基本数据类型是最有争议的设计决定之一,关于这个决定讨论的文章和帖子比比皆是。2011年9月,Simon Ritter在JAX London上的演讲说,要认真考虑在Java未来的某个版本中删除基本数据类型。接下来,我会简要介绍基本数据类型和Java的双类型系统。通过示例代码和简单的基准测试说明为什么基本数据类型对于某些类型的应用程序是必须的。我也会对Java与Scala、C++和JavaScript性能做一些比较。

测量软件性能

软件性能经常用时间和空间来衡量。时间可以是实际的运行时间,比如3.7分钟,或者是基于输入规模的时间复杂度,比如O(n2)。对于空间的衡量也是如此。经常用内存消耗来衡量,有时候也会扩大到磁盘的使用。改善性能经常要做时间和空间的折衷,缩短时间经常会对空间造成损害,反之亦然。时间复杂度取决于算法,把包装类型切换成基本数据类型对结果不会有任何改变,但是使用基本数据类型取代对象类型能改善时间和空间的性能。

基本数据类型vs对象类型

当你阅读这篇文章的时候,可能已经知道了Java是双类型的系统,也就是基本数据类型和对象类型,简称基本类型和对象。Java中有8个预定义的基本类型,它们的名字都是保留的关键字。常见的基本类型有int、double和boolean。Java中所有其他的类型包括用户自定义的类型,它们必然也是对象类型(我说”必然”是因为数组类型有点例外,与基本类型比数组更像是对象类型)。每一个基本类型都有一个对应的对象包装类,比如int的包装类是Integer,double的包装类是Double,boolean的包装类是Boolean。基本类型基于值,而对象类型则基于引用。与基本类型相关的争议都源于此。为了说明它们的不同,先来看一下两个声明语句。第一个语句使用的是基本类型,第二个使用的是包装类。
int n1 = 100;
Integer n2 = new Integer(100);
使用新添加到JDK5的特性自动装箱以后,第二个声明可以简化成:
Integer n2 = 100;
但是,底层的语义并没有发生改变。自动装箱简化了包装类的使用,减少了程序员的编码量,但是对运行时并没有任何的改变。图1展示了基本类型n1和包装对象类型n2的区别。



图1. 基本类型vs对象类型的内存结构

n1持有一个整数的值,但是n2持有的是对一个对象的引用,即那个对象持有整数的值。除此之外,n2引用的对象也包含了一个对Double对象的引用。

基本数据类型存在的问题

在我试图说服你需要基本类型之前,首先我应该感谢不同意我观点的那些人。Sherman Alpert在”基本类型是有害的(Primitive types considered harmful)”这篇文章中说基本类型是有害的,因为“它们把函数式的语义混进了面向对象模型里面,让面向对象变得不纯。基本类型不是对象,但是它们却存在于以一流对象为根本的语言中”。基本类型和(包装类形式的)对象类型提供了两种处理逻辑上相似的类型的方式,但是在底层的语义上却有着非常大的不同。比如,两个实例如何来比较相等性?对于基本类型,使用==操作符,但是对于对象类型,更好的方式是调用equals()方法,而基本类型是没有这个操作的。相似的,在赋值和传参的语义上也是不同的。就连默认值也是不一样的,比如int的默认是值0,但是Integer的默认值是null。关于这个话题的更多的背景可以参考Eric Bruno的博客”关于基本类型的讨论(A modern primitive discussion)”,里面总结了关于基本类型的正反两方面的意见。Stack Overflow上也有很多关于基本类型的讨论,包括”为什么人们仍然在Java中使用基本类型?(Why do people still use primitive types in Java?)”,”有没有只使用对象不使用基本类型的理由?(Is there a reason to always use Objects instead of primitives?)”。Programmers Stack Exchange上也有一个类似的叫做”Java中什么时候应该使用基本类型和对象类型?(When to use primitive vs class in Java?)”的讨论。

内存的使用

Java中的double总是占据内存的64个比特,但是引用类型的字节数取决于JVM。我的电脑运行64位Win7和64位JVM,因此在我的电脑上一个引用占用64个比特。根据图1,一个double比如n1要占用8个字节(64比特),一个Double比如n2要占用24个字节――对象的引用占8个字节,对象中的double的值占8个字节,对象中对Double对象的引用占8个字节。此外,Java需要使用额外的内存来支持对象的垃圾回收,但是基本类型不需要。下面让我们来验证下。修改列表1中的代码(没有列出来),改变矩阵的元素类型,我们也可以测量一个nn的Double类型的矩阵所占的字节数。在我的电脑上用10001000的矩阵来测试这两个方法,我得到了表1的结果。就像之前说的那样,基本类型版本的double矩阵中每一个元素占8个多字节,跟我预期的差不多,但是,对象类型版本的Double矩阵中每一个元素占28个字节还要多一点。因此,在这个例子中,Double的内存使用是double的3倍还要多,这对那些明白上面图1说的内存布局的人来说,并不是一件让人很吃惊的事情。
表1. double和Double的内存使用情况对比
版本总字节数平均字节数
使用double8,380,7688.381
使用Double28,166,07228.166

运行时性能

为了比较基本类型和对象类型的运行时性能,我们需要一个数值计算占主导的算法。本文中,我选择了矩阵相乘,然后计算1000*1000的矩阵相乘所需要的时间。我用一种很直观的方式来编码double类型的矩阵相乘,就像列表2中展示的那样。可能会有更快的方式来实现矩阵相乘(比如使用并发),但那个与本文无关。我需要的仅仅是两个很简单的方法,一个使用基本类型的double,另一个使用包装类Double。Double类型的矩阵相乘的代码跟列表2非常相似,仅仅是改了类型。在我的计算机上分别用两个方法对两个1000*1000的矩阵做多次乘法,测量执行时间。表2中列出了平均时间。可以看出来,在本例中,double的运行时性能是Double的四倍。这是一个不能忽略的很大的不同!
版本秒数
使用double11.31
使用Double48.48

结论

当18年前Java第一次登上历史舞台的时候,对于以数值计算为主的应用程序从性能的角度来说,它并不是最好的语言。但时过境迁,随着其他领域技术的发展,比如即时编译(aka自适应或动态编译),当使用基本数据类型的时候,这类Java应用的性能已经可以匹敌编译成本地代码的那些语言。并且,基本数据类型不需要垃圾回收,因此比对象类型多了另一个性能优势。表4总结了矩阵相乘基准测试在我的计算机上的运行时性能。还有其他的诸如可维护性可移植性和开发者擅长等因素让Java成为许多这类应用的很好地选择。表4. 矩阵相乘基准测试的运行时性能结果(以秒计)
C++Java
(double)
ScalaJavaScriptJava
(Double)
7.5811.3112.3015.9148.48
就像前面讨论的那样,看上去Oracle似乎很严肃的考虑了是否在Java未来的版本中去掉基本数据类型。除非Java编译器能产生跟基本数据类型性能相当的代码,我认为把基本数据类型从Java中去掉会妨碍Java在某些类型应用中的使用,即那些以数值计算为主的应用。本文中,我对矩阵相乘做了基准测试,还用更科学的基准测试SciMark2.0来支持这一点。

附录

在本文发表在JavaWorld上几周以后,作者收到了来自Brian Goetz的邮件。Brian Goetz是Oracle的Java语言架构师,他说从Java中移除基本数据类型不在考虑范围之内。移除基本数据类型的说法源自于对Java未来版本的愿景讨论的误解或者是不准确的解释。

关于作者

John I. Moore, Jr.是Citadel的一位数学和计算机教授,他在工业领域和学术上都有很丰富的经验,在面向对象技术,软件工程和应用数学方面有独到的专长。在超过30年的时间里,他使用关系型数据库和很多高级语言来设计和开发软件,工作中广泛使用从1.1开始的Java的各个版本。他对计算机科学的很多高级话题都开设并教授了许多课程和研讨班。
原文链接: javaworld 翻译: ImportNew.com - miracle1919
译文链接: http://www.importnew.com/11915.html
[ 转载请保留原文出处、译者和译文链接。]
原文出处:http://www.importnew.com/11915.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: