Java之 int与Integer

区别

int是java的8个基本数据类型(byte 1字节,short 2字节,int 4字节,long 8字节,float,double,boolean)之一。
Integer是int对象的包装类,有一个int类型的字段存储数据,并且提供了基本操作,如数学运算、int和字符串直接的转换。java5 引入boxing/unboxing,java可以根据
上下文进行自动转换,极大简化编程。

Integer值缓存范围

Integer值缓存,是java5另一个改进。改进Integer对象传统方式是直接调用构造器,直接new一个对象。根据实践,发现其操作都在有限、较小范围数值内
故java5新增静态工厂方法valueOf,在调用时会利用一个缓存机制,代理明显性能根据,该值默认缓存时-128~127直接

自动拆、装箱

自动装箱算是一种语法糖,可简单理解java平台为我们自动做了一些转换(如jvm语言scala的隐式转换),保证不同的写法在运行时等价,其发生编译阶段,即生成的字节码是一致的
如之前的整数,javac替我们自动把装箱转换为Integer.valueOf(),把拆箱替换为Integer.intValue。从另一方面,既然是调用的是Integer.valueOf,自然能够得到缓存好处。

例子

可以用如下例子进行反编译查看是否进行自动转换(自动拆箱)
Integer integer = 1;
int  unboxing = integer++;

反编译会有如下结构(不同jdk版本会有些微差异)

1: invokestatic  #2                  // Method
java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
8: invokevirtual #3                  // Method
java/lang/Integer.intValue:()I

包装类的缓存机制

  • 这些缓存机制不只Integer才有,同样存在于其他的一些包装类
  • Boolean,缓存true/false对应实例,确切说是只返回两个常量实例 Boolean.TRUE/FALSE.
  • Short,同样是缓存了-128 到127之间的数值
  • Byte数值有限,所以全部被缓存
  • Character,缓存范围’\u0000’到’\u007F’

自动装箱/拆箱的编程实践

  • 避免无意中的装箱、拆箱行为,
尤其在性能敏感场合。如创建10万个java对象和10万个整数开销不在同一个数量级。
仅仅对象头的内存使用就不小了。所以在性能敏感场合,使用基本数据类型代替包装类、动态数组(ArrayList)等作为性能优化备选项。
进而避免创建过多对象。如下计数器程序。
class CompactCounter{
		private volatile long counter;
		private static final AtomicLongFileUpdate<CompactCounter> update = AtomicLongFileUpdate.newUpdater(CompactCounter.class,"counter");
		public void increase(){
				updater.increateAndGet(this); //当前对象updater成员
		}
}	

源码分析

  • 考察Integer职责,如最大值、最小值,位数;静态工厂方法valueOf(),获取环境变量数值的方法,各种转换方法Parse(),进制转换
  • Integer缓存范围默认是-128 到 127 如果使用更大的数值
可以调整缓存上限值:JVM 参数 -XX:AutoBoxCacheMax=N
  • 上述JVM参数值在Integer静态初始化代码块里面
  • 包装类变量值的不可变性
字符串设计实现时,字符串是不可变的,保证基本的信息安全和并发编程安全。包装类里面的成员变量"value",在 Integer或Boolean等,都被声明private final,同样为不可变类型
该设计可以避免程序更改包装类的value,保证应用的可靠性。

d).无需担心包装类、原始数据类型位数差异

java开发中,因为Integer等包装类定义了类似SIZE或BYTES等常量。无需担心数据位数差异,如基本数据类型,包装类的位数差异,而C、C++必须考虑32位,64位平台差异

原始类型线程安全

原始类型数据安全访问

若保证原始数据类型线程安全,必须使用并发相关手段,如使用AtomicInteger,AtomicLong等线程安全类,通过提供硬件级别的原子操作,不会被其他线程打断,并且其value是valotile修饰,修改是线程间可见
在内存值v,线程保存的副本A相等时,将其值改为新值B,修改后对其他线程可见。对于ABA问题,使用AtomicStamperRefernce来标记是否被修改,通过变量值得版本来判断、保证CAS的准确性,有点鸡肋,并且大部分
ABA问题不影响程序并发,可以使用传统的互斥同步可能会比原子类更高效。

部分比较宽的数据类型

如float,double,甚至不能保证更新操作的原子性,可能程序读取到只更新了一半数据位的数值。

Java原始数据类型和引用类型局限性

原始数据类型和Java泛型不能配合使用

java泛型在某种程度上可以作为伪泛型,它完全是一种编译期技巧,Java编译期自动会将类型转换为对应类型,七绝刀使用泛型,必须保证相应类型可以转换为object

无法高效表达数据,复杂数据结构

无法表达高效表达数据、复杂数据结构,如vector,tuple。因为java对象都是引用类型,如果一个原始数据类型数组,它在内存是一组连续内存,对象数组存储的是引用,往往非连续内存存储。
该设计虽然带来极大灵活性,但也导致数据低效操作,无法使用CPU缓存机制。虽然java为对象根据各种多台,线程安全方面的支持,但并不满足所有场合需求
尤其是日益增加数据数据处理量级。
发布了150 篇原创文章 · 获赞 15 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/dymkkj/article/details/104452658