Java 数据类型和面试

类型大小 bit范围默认值
byte8-128 ~ 1270
short16-32768 ~ 327670
int32-2,147,483,648 ~ 2,147,483,6470
long64- 2^63 ~ 2^63 - 10L
float321.4E-45 ~ 3.4028235E380.0f
double644.9E-324 ~ 1.7976931348623157E3080.0d
boolean8true, falsefalse
char16 位 Unicode 字符0 ~ 65535\u0000

问题 1

byte a = 127;
a += 1;
System.out.println(a);

为了弄清楚这个问题,我们先来了解一下 每个数据所能表示的大小以及范围是怎么来的,以 byte 为例

01111111
符号位 0 正 1 负

上面的内存形式表现了一个字节所能存储的最大的正数,
1 ∗ 2 0 + 1 ∗ 2 1 + 1 ∗ 2 2 + . . . + 2 6 = ∑ n = 0 6 a n = a 1 ( 1 − q n ) 1 − q = 1 ∗ ( 1 − 2 7 ) 1 − 2 = 2 7 − 1 = 127 1 * 2^0 + 1 * 2^1 + 1 * 2^2 + ... + 2^6 = \sum_{n=0}^{6}{a^n} = \frac {a_1(1 - q^n)} {1- q} = \frac {1 * (1 - 2^7)}{ 1- 2} = 2^7 - 1 = 127 120+121+122+...+26=n=06an=1qa1(1qn)=121(127)=271=127
按照上面的方式,我们计算一下最小值,只需要把符号位变成1就可以了

11111111
符号位 0 正 1 负

计算结果为 -127, 不对啊, 哪出问题了?

00000000
符号位 0 正 1 负
10000000
符号位 0 正 1 负

当处于这两个状态的时候,我们可以理解为 +0 和 -0,是不是有点重复了, 把负数的范围缩小1,就能够避免两个 0的出现了。 -0 - 1 ~ -127 - 1 = -1 ~ -128

把原来的 0 ~ 127 和 -0 ~ -127 改成 0 ~ 127 和 -1 ~ -128 更合理,那么最终的范围就变成 - 128 ~ 127 了

但-128在内存中该怎么表示呢?

我们以最开始的那个题的答案就是-128,那我们就以它们在内存中的形式来讨论这个-128是怎么来的。

首先我们要清楚一点,计算机中的数的数据都是以补码的形式存储的,至于为什么用补码,那就是更方便,更容易易计算。

正数的 原码, 补码, 反码都是一样的, 如 1

原码00000001
反码00000001
补码00000001

负数的补码是在原码的基础是除符号位外,所有的位取反。 补码则是在反码的基础上末位加1. -1的补码如下:

原码10000001
反码11111110
补码11111111

1 - 1 我们可以理理解成 1 + (-1), 结果就是 0 0 0 0 0 0 0 0, 那就是 0了。

原码01111111
100000001
127 + 110000000

内存中结果的补码的形式就是 1 0 0 0 0 0 0 0, 还原成源码是 1 0 0 0 0 0 0 0. 所以我们可以认为机器会把 -0 解析成该范围表示的一个最小数,如这里就是 -2^7.如果是16位那么就是 10000000 00000000,那所表示的就是 -2^15了。

按照上面的计算,我们可以再看一下 127 + 2, 结果 应该就是 -127

12701111111
200000010
127 + 110000001

还原成 反码 为 1 0 0 0 0 0 0 0 , 原码为 1 1 1 1 1 1 1 1 , 那值就是 -127 了。

问题2

Integer a = 40;
Integer b = 40;
System.out.println(a == b);  true

两个对象的指针居然是一个, why?

在我们的8种基本类型的包装类中,除了float和double以外,都实现了常量池,如果取的值在[-128, 127]中,那么这些值就会从常量池中取出,不会再生成一个新的对象

//Integer 缓存代码 :
public static Integer valueOf(int i) {
        assert IntegerCache.high >= 127;
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

当我们用 Integer a = 40;这种形式去生成一个Integer对象时,实际上是会调用 Interger 的valueOf 方法。

IntegerCache.high 应该等于 127, IntegerCache.low = -128,

IntegerCache.cache 包含的size为256, 下标为 0 ~ 255 的一个数组, 值为[-128, -127, -126, -125 … 127]。

所以上面的问题,其实两次拿到的都是 IntegerCache.cache[40+ (-IntegerCache.low)]的值,所以是同一个对象。

必须是使用上面那种形式,调用valueof才会去常量池中去取值。如果new 一个对象,则不会。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值