• 7、基本类型和包装类型


    Java 的 8 个原始数据类型(Primitive Types,boolean、byte 、short、char、int、float、double、long),Java 语言虽然号称一切都是对象,但原始数据类型是例外。

    Integer 是 int 对应的包装类,它有一个 int 类型的字段存储数据,并且提供了基本操作,比如数学运算、int 和字符串之间转换等。在 Java 5 中,引入了自动装箱和自动拆箱功能(boxing/unboxing),Java 可以根据上下文,自动进行转换,极大地简化了相关编程。

    关于 Integer 的值缓存,这涉及 Java 5 中另一个改进。构建 Integer 对象的传统方式是直接调用构造器,直接 new 一个对象。但是根据实践,我们发现大部分数据操作都是集中在有限的、较小的数值范围,因而,在 Java 5 中新增了静态工厂方法 valueOf,在调用它的时候会利用一个缓存机制,带来了明显的性能改进。按照 Javadoc,这个值默认缓存是 -128 到 127 之间。

    Integer.ValueOf(int)和new Integer(int)性能比较:https://blog.csdn.net/zhongweijian/article/details/5317375

    Integer.valueOf 和 Integer.parseInt 和 new Integer区别及注意事项https://www.cnblogs.com/hdwang/p/7009449.html

     

    相关问题:

    • Java 使用的不同阶段:编译阶段、运行时,自动装箱 / 自动拆箱是发生在什么阶段?

    • 静态工厂方法 valueOf 会使用到缓存机制,那么自动装箱的时候,缓存机制起作用吗?

    • 为什么我们需要原始数据类型,Java 的对象似乎也很高效,应用中具体会产生哪些差异?

    • 阅读过 Integer 源码吗?分析下类或某些方法的设计要点。

    1. 自动装箱、拆箱

    自动装箱实际上算是一种语法糖。什么是语法糖?可以简单理解为 Java 平台为我们自动进行了一些转换,保证不同的写法在运行时等价,它们发生在编译阶段,也就是生成的字节码是一致的。

    像前面提到的整数,javac 替我们自动把装箱转换为 Integer.valueOf(),把拆箱替换为 Integer.intValue(),这似乎这也顺道回答了另一个问题,既然调用的是 Integer.valueOf,自然能够得到缓存的好处啊。

    这种缓存机制并不是只有 Integer 才有,同样存在于其他的一些包装类,比如:

    • Boolean,缓存了 true/false 对应实例,确切说,只会返回两个常量实例 Boolean.TRUE/FALSE。

    • Short,同样是缓存了 -128 到 127 之间的数值。

    • Byte,数值有限,所以全部都被缓存。

    • Character,缓存范围 'u0000' 到 'u007F

    自动装箱 / 自动拆箱注意:

    原则上,建议避免无意中的装箱、拆箱行为,尤其是在性能敏感的场合,创建 10 万个 Java 对象和 10 万个整数的开销可不是一个数量级的,不管是内存使用还是处理速度,光是对象头的空间占用就已经是数量级的差距了。使用原始数据类型、数组甚至本地代码实现等,在性能极度敏感的场景往往具有比较大的优势,用其替换掉包装类、动态数组(如 ArrayList)等可以作为性能优化的备选项。一些追求极致性能的产品或者类库,会极力避免创建过多对象。当然,在大多数产品代码里,并没有必要这么做,还是以开发效率优先。

    java静态工厂方法https://www.jianshu.com/p/ceb5ec8f1174

    最常用的是通过new方法构建Integer对象。但是,基于大部分数据操作都是集中在有限的、较小的数值范围,在JDK1.5 中新增了静态工厂方法 valueOf,其背后实现是将int值为-128 到 127 之间的Integer对象进行缓存,在调用时候直接从缓存中获取,进而提升构建对象的性能,也就是说使用该方法后,如果两个对象的int值相同且落在缓存值范围内,那么这个两个对象就是同一个对象;当值较小且频繁使用时,推荐优先使用整型池方法(时间与空间性能俱佳)。

    注意事项

    [1] 基本类型均具有取值范围,在大数*大数的时候,有可能会出现越界的情况。
    [2] 基本类型转换时,使用声明的方式。例:long result= 1234567890 * 24 * 365;结果值一定不会是你所期望的那个值,因为1234567890 * 24已经超过了int的范         围,如果修改为:long result= 1234567890L * 24 * 365;就正常了。
    [3] 慎用基本类型处理货币存储。如采用double常会带来差距,常采用BigDecimal、整型(如果要精确表示分,可将值扩大100倍转化为整型)解决该问题。
    [4] 优先使用基本类型。原则上,建议避免无意中的装箱、拆箱行为,尤其是在性能敏感的场合,
    [5] 如果有线程安全的计算需要,建议考虑使用类型AtomicInteger、AtomicLong 这样的线程安全类。部分比较宽的基本数据类型,比如 float、double,甚至不能保证更新操作的原子性,可能出现程序读取到只更新了一半数据位的数值。

    精确计算:

    在《Effective Java》这本书中也提到这个原则,float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用 java.math.BigDecimal。我们如果需要精确计算,非要用String来够造BigDecimal不可!在《Effective Java》一书中的例子是用String来够造BigDecimal的。

  • 相关阅读:
    [C/C++]Fibonacci numbers
    使用VS调试时,被调试进程如何被断下来的。
    Windows下动态加载可执行代码原理简述
    发个JD, 求人被我卖
    使用Windbg知道程序运行时的命令行参数.
    How to debug usermode process using kernelmode windbg in Win7
    This is a test
    多核时代,还在使用任务管理器来看程序的性能吗?
    六种异常处理的陋习
    巧记Java访问控制描述符(Access Control Modifier)public, private, protected
  • 原文地址:https://www.cnblogs.com/xuan5301215/p/9076377.html
Copyright © 2020-2023  润新知