Effective Java(3rd)-Item61 原始类型优于装箱类型

  Java有一个由两部分组成的类型系统,包括基本类型(如int、double和boolean)和引用类型(如String和List)。每个基本类型都有一个对应的引用类型,称为装箱原语。与int、double和boolean对应的装箱原语是Integer、double和boolean。
  正如第6项中提到的,自动装箱和自动拆箱模糊了基本类型和已装箱基本类型之间的区别,但不会消除它们。这两者之间有真正的区别,重要的是您要始终意识到您正在使用的是哪一种,并在它们之间仔细选择。
  基本类型和盒装基本类型之间有三个主要区别。首先,原语只有它们的值,而装箱的原语具有与其值不同的标识。换句话说,两个装箱的原语实例可以具有相同的值和不同的标识。第二,原语类型只有全功能值,而每个装箱的原语类型除了对应的原语类型的所有功能值外,还有一个非功能值,即null。最后,原语比盒装原语更节省时间和空间。如果你不小心的话,这三种差异都会给你带来真正的麻烦。
  考虑下面的比较器,它的设计目的是表示整数值上的升序数字。(回想一下,比较器的compare方法返回一个负数、零或正数,这取决于它的第一个参数是小于、等于还是大于第二个参数。)你不需要在实践中编写这个比较器,因为它实现了整数的自然排序,但它提供了一个有趣的例子:

image.png

  这个比较器看起来应该可以工作,它将通过许多测试。例如,它可以与集合一起使用。排序以正确地排序一个百万元素列表,无论列表是否包含重复的元素。但这个比较器存在严重缺陷。要使自己相信这一点,只需打印naturalOrder.compare(new Integer(42), new Integer(42))的值。两个整数实例都表示相同的值(42),所以这个表达式的值应该是0,但它是1,这表明第一个整数值大于第二个整数值!
  那么问题是什么呢?自然顺序中的第一个测试工作得很好。计算表达式i < j会使i和j引用的整数实例自动取消装箱;也就是说,它提取它们的原始值。评估继续到检查得到的第一个int值是否小于第二个int值。。但假设它不是。然后,下一个测试计算表达式i == j,该表达式对两个对象引用执行标识比较。如果i和j引用表示相同整型值的不同整数实例,这个比较将返回false,比较器将错误地返回1,表明第一个整型值大于第二个整型值。将==操作符应用于装箱的原语几乎总是错误的。
  在实践中,如果您需要一个比较器来描述类型的自然顺序,您应该简单地调用comparator . naturalorder(),如果您自己编写一个比较器,您应该使用比较器构造方法,或者对基本类型使用静态比较方法(item14)。也就是说,您可以通过添加两个局部变量来存储与装箱整数参数对应的原始int值,并对这些变量执行所有的比较,从而修复损坏的比较器中的问题。这避免了错误的身份比较:

image.png

  接下来,考虑一下这个有趣的小程序:


image.png

  不,它不会打印出Unbelievable——但它所做的几乎同样奇怪。它在计算表达式i == 42时抛出NullPointerException。问题是,i是整数,而不是整型数,而且像所有非常量对象引用字段一样,它的初值为null。当程序计算表达式i == 42时,它将整数与整数进行比较。在几乎所有情况下在操作中混合原语和装箱原语时,装箱原语是自动拆箱的。如果一个空对象引用是自动取消装箱的,那么您将得到一个NullPointerException。正如这个程序所演示的,它几乎可以在任何地方发生。修复这个问题非常简单,只需将i声明为int而不是整数。
  最后,考虑第24页第6项中的程序:

image.png

  这个程序比它应该的速度慢得多,因为它意外地声明了一个局部变量(sum),它是装箱的原始类型Long,而不是原始类型Long。程序在没有错误或警告的情况下编译,变量被反复装箱和不装箱,导致观察到的性能下降。
  在本项目中讨论的所有三个程序中,问题都是一样的:程序员忽略了原语和装箱原语之间的区别,并承担了后果。在前两个项目中,结果是彻底的失败;第三,严重的性能问题。
  那么,什么时候应该使用装箱原语呢?它们有几个合法的用途。第一个是作为集合中的元素、键和值。不能将原语放在集合中,因此必须使用装箱的原语。这是一般情况下的特例。在参数化类型和方法(第5章)中,必须使用装箱原语作为类型参数,因为该语言不允许使用原语。例如,不能将变量声明为ThreadLocal<int>类型,因此必须使用ThreadLocal<Integer>。最后,在进行反射方法调用时,必须使用装箱原语( item65

  总之,只要有选择,就应该优先使用原语,而不是盒装原语。原始类型更简单、更快。如果必须使用盒装原语,请小心!自动装箱减少了使用装箱原语的冗长,但没有减少危险。当您的程序使用==操作符比较两个装箱的原语时,它会执行标识比较,这几乎肯定不是您想要的。当您的程序执行混合类型计算时,涉及到已装箱和未装箱原语,它将执行拆箱操作当程序自动拆箱时,它可以抛出NullPointerException。最后,当您的程序将原始值框起来时,可能会导致代价高昂且不必要的对象创建。
本文写于2019.7.19,历时1天

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容

  • [{"reportDate": "2018-01-23 23:28:49","fluctuateCause": n...
    加勒比海带_4bbc阅读 767评论 1 2
  • 目录: Android:Android 0.*Android 1.*Android 2.*Android 3.*A...
    敲代码的令狐葱阅读 3,837评论 0 2
  • 曾经错过了你 天注定 让我遇见你 1.遇见了你 这个人怎么这么多的赞?好厉害!我才100多,她都九万多了!林子骁看...
    81740383d29d阅读 281评论 0 1
  • 每年冬天都听过这样一句话,今年的冬天是近几年最冷的一个冬天。气温真的是逐年变低还是人越来越怕冷。
    旭啊旭阅读 241评论 0 1
  • 兰亭集序 【作者】王羲之【朝代】魏晋 译文对照 永和九年,岁在癸丑,暮春之初,会于会稽山阴之兰亭,修禊事也。群贤毕...
    弥歌阅读 271评论 0 0