前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JAVA类Integer

JAVA类Integer

作者头像
用户6055494
发布2019-12-15 19:28:54
9080
发布2019-12-15 19:28:54
举报
文章被收录于专栏:AVAJAVAJ

今天带来的是Integer,想必大家都不会陌生,下面会大家从属性、内部类、好玩的几个方法入手,来简单解析下Integer这个类。

属性:

代表Integer边界的最大值MAX_VALUE和最小值MIN_VALUE

代码语言:javascript
复制
MIN_VALUE = 0x80000000
MAX_VALUE = 0x7fffffff
众所周知数值在计算机中以补码形式存储:
MIN_VALUE: 
补码:1000 0000 0000 0000 0000 0000 0000 0000
反码:1111 1111 1111 1111 1111 1111 1111 1111 = 补码 - 1 (最高位是符号位不能变哦)
原码:1000 0000 0000 0000 0000 0000 0000 0000 = -2^31
MAX_VALUE:
源码 = 反码 = 补码 :0111 1111 1111 1111 1111 1111 1111 1111 = 2^31 - 1
不太熟悉的小伙伴可能有点好奇:
MIN_VALUE -2^31
MAX_VALUE 2^31 - 1
这俩个怎么相差1呢?是这样的,当把符号位加入后为零的情况就出现了俩种
一种是 +0 一种是 -0,所以不能浪费啊,仔细看上面-2^31其实就是-0啦,是不是很巧妙!

VALUE 存储Integer的数值

SIZE 存储Integer是多少位(32位)

BYTES 就是说一个int是多少字节(8 * 4)4字节

上图中属性里还有一些char的数组,主要是用来方便后面方法的快速计算这里就不一一介绍,后面会给出几个例子。

内部类

IntegerCache:相信很多小伙伴从名字就能看出,这是个缓存,那么Integer为什么要这个缓存能?这个缓存的作用是什么呢?下面进行简单的介绍。

代码语言:javascript
复制
IntegerCache:
三个属性:
int low = -128;
int high; // 可从外部传入 默认是127
Integer cache[];
然后有个静态代码块,在类加载的时候运行:

static {
    // high value may be configured by property
    int h = 127;
    // 外部配置high,未配置默认127(上面的h)
    String integerCacheHighPropValue =
        sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
    if (integerCacheHighPropValue != null) {
        try {
            int i = parseInt(integerCacheHighPropValue);
            i = Math.max(i, 127);
            // 加上128个负数 最大不能超过Integer能表示的最大值
            h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
        } catch( NumberFormatException nfe) {
            // If the property cannot be parsed into an int, ignore it.
        }
    }
    high = h;

    cache = new Integer[(high - low) + 1];
    int j = low;
    for(int k = 0; k < cache.length; k++)
        cache[k] = new Integer(j++);

    // range [-128, 127] must be interned (JLS7 5.1.7)
    assert IntegerCache.high >= 127;
}
由代码来看负数的范围好像只能到-128

既然有缓存那么经典的例子就出现啦:
采用默认的high大小:
Integer i1 = 127;
Integer i2 = 127;
Integer i3 = 128;
Integer i4 = 128;
// 取缓存了
System.out.println(i1 == i2);// true
// 没得缓存取
System.out.println(i3 == i4);// false

下面就开始介绍一些好玩的方法啦:

valueOf()

代码语言:javascript
复制
// 返回数值i包装类型
publicstatic Integer valueOf(int i) {
    // 判断范围看是否能从缓存里拿
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
     // 缓存里没有的话直接建对象
    return new Integer(i);
}
由此可见以下代码也成立:
Integer i1 = Integer.valueOf(127);
Integer i2 = Integer.valueOf(127);
Integer i3 = Integer.valueOf(128);
Integer i4 = Integer.valueOf(128);
// 取缓存了
System.out.println(i1 == i2);// true
// 没得缓存取
System.out.println(i3 == i4);// false
请注意:下面这样的肯定不行
Integer i1 = new Integer(127);
Integer i2 = new Integer(127);
i1 == i2 // false
很明显是在new对象嘛,所以肯定是false咯!

getChars()

代码语言:javascript
复制
// 将int数字转换放进一个字符数组
static void getChars(int i, int index, char[] buf) {
  int q, r;
  int charPos = index;
  char sign = 0;
  // 如果是负数则转成正数 方便运算
  if (i < 0) {
      sign = '-';
      i = -i;
  }
  // 为什么这里要区分大于65536的呢?
  // 相对于除法运算计算机更喜欢乘法运算,当然如果能用加法最好不用乘除,影响性能,那用乘除法和这里区分
  // i的大小明显没啥关系啊,咋一看好像没什么关系,我们注意到在while循环里用的是除法i/100,前面提到
  // 计算机更加喜欢性能高的乘法,所以这里把i分块是为了让后面的i做乘法运算。那问题来了,为什么不直接
  // 做乘法运算呢?仔细看代码,发现这里用的是 i - 10*(i/10)由于i是int类型会抛弃余数,这样减法得出i的个位数,从而换成char字符,
  // 当然当i>=65536的时候是进行俩位一起转换
  // 
  // Generate two digits per iteration
  while (i >= 65536) {
      // 每次处理俩个字符
      q = i / 100;
  // really: r = i - (q * 100);
      r = i - ((q << 6) + (q << 5) + (q << 2));
      i = q;
      // 这里看了DigitOnes和DigitTen数组你就会豁然开朗了下面贴出来
      buf [--charPos] = DigitOnes[r];
      buf [--charPos] = DigitTens[r];
  }
  
  // Fall thru to fast mode for smaller numbers
  // assert(i <= 65536, i);
  for (;;) {
      // 这里是做乘法运算2的19次方是52488  这里相当于i * 52429/524288 这样相当于i/10这个操作了
      // 这里们其实可以找出很多对 如 104858/1048576(2的10次方) 209716/2097152(2的21次方)而且这些式子得出结果的精度也差不多,
      // 那么现在就要考虑i的问题,前面已经说了计算机对乘法运算更加喜爱,所以这里我们尽可能的让i大,所以我们要尽可能的把与i相乘
      // 的这个数(52429)缩小,但是精度要高一点,不然会有误差。
      q = (i * 52429) >>> (16+3);
      r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...
      buf [--charPos] = digits [r];
      i = q;
      if (i == 0) break;
  }
  if (sign != 0) {
      buf [--charPos] = sign;
  }
}
// 上面出现了这俩行代码:
buf [--charPos] = DigitOnes[r];
buf [--charPos] = DigitTens[r];
举个例子比如: 
buf [--charPos] = DigitOnes[67];
buf [--charPos] = DigitTens[67];
  final static char [] DigitTens = {
  '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
  '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
  '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
  '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
  '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
  '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
  '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
  '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
  '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
  '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
  } ;
final static char [] DigitOnes = {
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  } ;
  有没有被惊艳到啊?

stringSize()

代码语言:javascript
复制
// 求十进制表示几位数
static int stringSize(int x) {
    for (int i=0; ; i++)
        if (x <= sizeTable[i])
            return i+1;
}
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                                      99999999, 999999999, Integer.MAX_VALUE };

highestOneBit()

代码语言:javascript
复制
// 取最高位的1其他全取0 如 14 = 1110 = 8+4+2=14
// highestOneBit(14) 会返回8 1000 因为只要最高位的1其他全0 
public static int highestOneBit(int i) {
    // HD, Figure 3-1
    i |= (i >>  1);
    i |= (i >>  2);
    i |= (i >>  4);
    i |= (i >>  8);
    i |= (i >> 16);
    //上面这段代码就是将你最高位的1往所有低位复制 
    //如 100000 运行完就是111111
    
    // 11111 - 01111
    return i - (i >>> 1);
}
类似的代码在HashMap里有个tableSizeFor(int cap)方法用来找
最接近cap且大于cap的2的幂的数值 如 
cap = 11 返回 16 2^4
cap = 24 返回 32 2^5

和上面这个方法一对的

lowerOneBit()

代码语言:javascript
复制
    public static int lowestOneBit(int i) {
        // HD, Section 2-1
        return i & -i;
    }
    6 & -6 = 2
    int有32位 前面的0自行脑补哈!
    6 = 0000...110
    -6 = 1111...010 // 计算机存的是补码哈
    &一下就是 0000....10 = 2 这就取到最低位的1 其他位全置零

numberOfLeadingZeros()

代码语言:javascript
复制
// 求一个数二进制的表示 前面有多少零
public static int numberOfLeadingZeros(int i) {
    // HD, Figure 5-6
    if (i == 0)
        return 32;
    int n = 1;
    // 前16位为零的话 就剔除这16个
    if (i >>> 16 == 0) { n += 16; i <<= 16; }
     // 前8位为零的话 就剔除这8个
    if (i >>> 24 == 0) { n +=  8; i <<=  8; }
     // 前4位为零的话 就剔除这4个
    if (i >>> 28 == 0) { n +=  4; i <<=  4; }
     // 前2位为零的话 就剔除这2个
    if (i >>> 30 == 0) { n +=  2; i <<=  2; }
    // 最后一个
    n -= i >>> 31;
    return n;
}

最后留个作业:求一个数的二进制表示中1的个数,方法在下面给出了:

代码语言:javascript
复制
public static int bitCount(int i) {
    // HD, Figure 5-2
    i = i - ((i >>> 1) & 0x55555555);
    i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
    i = (i + (i >>> 4)) & 0x0f0f0f0f;
    i = i + (i >>> 8);
    i = i + (i >>> 16);
    return i & 0x3f;
}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员面试鸭 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档