Java学习笔记 - JDK学习Byte、Short、Integer、Long、Boolean等基本数据类型

int是我们常说的整形数字,是Java的8个原始数据类型(Primitive Types,boolean、byte 、short、char、int、foat、double、long)之一。 Java语言虽然号称一切都是对象,
但原始数据类型是例外。

1、自动拆装箱的概念;

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

demo:

自动装箱:Integer a = 5;  --→  Integer a =  new Integer(5);   

自动拆箱:Integer a = 5;  --→ 可以直接赋值给基本数据类型 int n = a;

从反编译得到的字节码内容可以看出,在装箱的时候自动调用的是Integer的valueOf(int)方法。而在拆箱的时候自动调用的是Integer的intValue方法,其他类型也一样。

2、关于Integer.valueOf() 的 -128~127 缓存;

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

但是根据源码:

Integer a = 1;//自动走缓存装箱

Integer a = new Integer(1);//在堆区内存中生成新实例,是不走缓存的

这种缓存行为不仅适用于Integer对象。我们针对所有的整数类型的类都有类似的缓存机制。

有ByteCache用于缓存Byte对象

有ShortCache用于缓存Short对象

有LongCache用于缓存Long对象

有CharacterCache用于缓存Character对象

ByteShortLong有固定范围: -128 到 127。对于Character, 范围是 0 到 127。

根据源码除了Integer以外,其他都是final修饰这个范围都不能改变。

Integer的cache范围可以通过修改JVM

sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high")

配置实现。

3、无/有符号类型,>>,<<,&/^/|运算,原码/反码/补码运算;

A、有/无符号类型

有些整形是无符号的,例如年龄,有些整形需要符号,类似库存,在C语言里面都是有Unsign变量的,但是在Java里是没有的,但是在Java8之后 在增加了无符号转换。

有符号数 二进制 首位代表 正负,1为负数,0位正数。无符号数字没有代表正负的首位

Byte、Integer有符号转换成无符号,范围都变大了。

有符号Integer:范围 -2^16 ~ 2^16 - 1

无符号Integer:范围 0 ~ 2^32 - 1 

因此源码中Integer转换成无符号就变成有符号的Long了

public static long toUnsignedLong(int x) {
    return ((long) x) & 0xffffffffL;
}
@Native public static final long MAX_VALUE = 0x7fffffffffffffffL;//01111111111111111111111111111111  = 2^32次方 - 1 

其中0xffffffffL 是Long.MAXVALUE 也就是Long有符号数的最大值 ,然后进行&运算 

0101101001与011111111111进行与运算,根据0 1 得 0 ,1 1得1的原则就得到了无符号数;

Byte与此类似

public static int toUnsignedInt(byte x) {
    return ((int) x) & 0xff;
}

B、<<和>>带符号位移运算,无符号>>>位移运算

<<左移运算:

byte a = 2; a=<<1 表示 a 向左移一位表示乘2一次方也就是 00000010 → 00000100 = 4,左边丢弃,右边补0,以此类推,a=<<2 乘以2的二次方= 8;

>>右移运算:

与上相反,a=a>>1代表除以2的一次方,a=a>>2代表除以2的二次方,右边丢弃,左边补充一个符号位,正数补0,负数补1;

>>>无符号位移运算:

>>>运算符把 expression1 的各个位向右移expression2 指定的位数。右移后左边空出的位用零来填充。移出右边的位被丢弃。

20 >>> 2  补码(由原码按位取反,末尾加1):00000000,00010100 右移:00000000,00000101(高位补0) 结果:5

C、&/|/^运算

&与运算: 两位都是1得1,两位有一个0都得0;

|或运算:两个有一个为1就是1;

^异或运算:两个相同(11,00)为0.两个不一样为1;

~取反运算符: ~0=1,~1=0;

4、Integer等整形占用的内存大小

在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding), Class对象指针。

HotSpot虚拟机的对象头包括两部分信息,第一部分用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,

这部分数据的长度在32位和64位的虚拟机(未开启压缩指针)中分别为32bit(4字节)和64bit(8字节),官方称它为"Mark Word"。对象头的另外一部分是类型指针,即对象指向它的类元数据的指针,虚拟机

通过这个指针来确定这个对象是哪个类的实例。第三部分对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍。

1. Mark Word:标记位 4字节,类似轻量级锁标记位,偏向锁标记位等。
2. Class对象指针:4字节,指向对象对应class对象的内存地址。
3. 对象实际数据:对象所有成员变量。
4. 对齐:对齐填充字节,按照8个字节填充。
Integer占用内存大小,4+4+4+4=16字节。

5、整型数据线程安全问题

原始数据类型以及引用数据类型的整型变量,显然要使用并发相关手段,例如volatile等修饰,才能保证线程安全,如果有线程安全的计算需要建议使用AutomicInteger、AutomicLong等这样子的线程安全类;

 

由以上学习总结出的日常使用注意事项:

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值