典型回答
Java 语言虽然号称一切都是对象,但原始数据类型是例外。
Java 的 8 个原始数据类型(Primitive Types,boolean、byte 、short、char、int、float、double、long)之一。
Integer 是 int 对应的包装类,它有一个 int 类型的字段存储数据,并且提供了基本操作,比如数学运算 ,int和字符串之间的转换等。
自动装箱和自动拆箱(boxing/unboxing): 根据上下文,自动进行转换,极大地简化了相关编程。
Integer 的值缓存:大部分数据操作都是集中在有限的、较小的数值范围。调用它的时候会利用一个缓存机制,带来了明显的性能改进。这个值默认缓存是 -128 到 127 之间。
理解自动装箱、拆箱
自动装箱实际上算是一种语法糖。什么是语法糖?可以简单理解为 Java 平台为我们自动进行了一些转换,保证不同的写法在运行时等价,它们发生在编译阶段,也就是生成的字节码是一致的。
javac 替我们自动把装箱转换为 Integer.valueOf(),把拆箱替换为 Integer.intValue()。
这种缓存机制并不是只有 Integer 才有,同样存在于其他包装类:
- Boolean,缓存了 true/false 对应实例,Boolean.TRUE/FALSE
- Short,同样是缓存了 -128 到 127 之间的数值。
- Byte,数值有限,所以全部都被缓存
- Character,缓存范围’\u0000’ 到 ‘\u007F'
建议避免无意中的装箱、拆箱行为,尤其是在性能敏感的场合。
使用原始数据类型、数组甚至本地代码实现等,在性能极度敏感的场景往往具有比较大的优势,用其替换掉包装类、动态数组(如 ArrayList)等可以作为性能优化的备选项。
源码分析
Integer 的缓存范围虽然默认是 -128 到 127,缓存上限值实际是可以根据需要调整的,JVM 提供了参数设置:
-XX:AutoBoxCacheMax=N
包装类的值是不可变的,都被声明为“private final”。
Integer 等包装类,定义了类似 SIZE 或者 BYTES这样的常量,代表数据类型存储的bits和bytes。不管是 32 位还是 64 位环境,开发者无需担心数据的位数差异。
原始类型线程安全
原始数据类型的变量,要使用并发相关手段,才能保证线程安全。建议使用AtomicInteger、AtomicLong 这样的线程安全类。
部分比较宽的数据类型,比如 float、double,甚至不能保证更新操作的原子性,可能出现程序读取到只更新了一半数据位的数值。
Java 原始数据类型和引用类型局限性
-
原始数据类型和 Java 泛型并不能配合使用
Java的泛型是一种编译期的技巧(检查),Java 编译期会自动将类型转换为对应的特定类型,这就决定了使用泛型,必须保证相应类型可以转换为 Object。 -
无法高效地表达数据,也不便于表达复杂的数据结构
更加高密度的值类型是非常现实的需求
网友评论