JDK源码笔记01 Integer

something before start

写这个系列博客主要的目的是记录一下学习JDK的过程,一方面方便后面使用,另一方面则是避免草草过去。代码版本是jdk14
顺序大概是:包装类--字符串--集合类--juc并发包--io--网络编程--注解--stream--类加载--反射--文件操作处理类

方法以及子类概览

构造函数

public Integer(int value) //不建议使用,建议使用valueOf。自动装箱的时候调用的也是valueOf
public Integer(String s) //不建议使用,建议使用valueOf

输出字符串

有一些内容比较少的直接在这里用注释说明了:D

toString(int i) 十进制的toString,一次处理两位,相对toString(int i, int radix)性能更好一点点吧,少做了一些除法
toString(int i, int radix)
toStringUTF16(int i, int radix)
toUnsignedString(int i, int radix) 里面调用了Long的方法
toUnsignedString0(int i, int shift) shift是代表radix = 2^shift, 取值(0,5]
toHexString(int i) 返回无符号16进制字符串,里面调用了toUnsignedString0
toOctalString(int i)返回无符号8进制字符串
toBinaryString(int i)返回无符号2进制字符串

getChars(int i, int index, byte[] buf) index就是size,该方法将十进制转换成字节数组存入buf,返回开始位置

解析字符串

public static int parseInt(CharSequence s, int beginIndex, int endIndex, int radix)
public static int parseInt(String s, int radix)
public static int parseInt(String s) //十进制

public static int parseUnsignedInt(String s, int radix) //将非负整数转换成整数表示
public static int parseUnsignedInt(CharSequence s, int beginIndex, int endIndex, int radix)

public static Integer valueOf(int i) 
public static Integer valueOf(String s)  //调用parseInt之后传入valueOf(int i) 
public static Integer valueOf(String s, int radix) //同上

杂七杂八函数

  1. hash和equal
哈希值就是value
public static int hashCode(int value) {
       return value;
   }
equal 就是比较value
public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}
  1. getInteger
//获取系统的参数,nm即参数名称,空则返回val
//内部调用了System.getProperty(nm),如果存在,则调用decode转换成Integer返回
public static Integer getInteger(String nm, Integer val)
  1. decode
    将字符串转换成Integer,支持十进制,八进制,十六进制
    十六进制:0x 0X #
    八进制:0
    加减号:+ -
public static Integer decode(String nm)
//1 取出正负号
//2 通过枚举判断出是什么进制的字符串,通过valueOf获得相应的值
//3 数字和字母部分最终通过parseInt得到
//4 把正负号放回到数字里
  1. compare
compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
  1. compareUnsigned
return compare(x + MIN_VALUE, y + MIN_VALUE);
  1. highestOneBit(int i) 取出最高位
  2. lowestOneBit(int i) return i & -i; 很妙
  3. bitCount(int i) 获取1的数目,用的是分治策略 很美,可以参照这个博客 理解一下
    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;
    }
  1. rotateLeft(int i, int distance) 向左边循环
  2. rotateRight
  3. reverse 每位都翻转,也是分治策略 很美:D
  4. reverseBytes 翻转字符
  5. signum 取出符号,返回1 或 -1
  6. numberOfLeadingZeros 返回i高位的0的数目
  7. numberOfTrailingZeros 返回i低位的0的数目

方法详解

输出字符串

toString(int i, int radix)

签名public static String toString(int i, int radix)
功能:返回radix进制的字符串
参数
i:十进制正整数
radix:基数,若要转换成16进制则为16
问题
1. 明明用正数一样可以实现,为什么要转换成负数?
因为补码里负数多一位,如果改成正数会有bug
2. 我实现的时候发现StringLatin1这个类用不了,为什么?
傻了,因为他不是public 😄

说明:思路就是短除法,把结果放到byte[]里,然后返回一个String
主要代码

    public static String toString(int i, int radix) {
//最小2  最大36
        if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
            radix = 10;

        /* Use the faster version */
//若radix=10 直接整就行了
        if (radix == 10) {
            return toString(i);
        }

//COMPACT_STRINGS由jvm决定, false的话会转换成utf16的字符串
        if (COMPACT_STRINGS) {
            byte[] buf = new byte[33];
            boolean negative = (i < 0);//判断是否为负数
            int charPos = 32;
//如果是正数则转换成负数
            if (!negative) {
                i = -i;
            }
//短除法,将每一位的数值相应的字符放进 buf[]  从后往前放
//digits里面存放的是每位数字相应的字符
            while (i <= -radix) {
                buf[charPos--] = (byte)digits[-(i % radix)];
                i = i / radix;
            }
//最后一位放进 buf[]
            buf[charPos] = (byte)digits[-i];
//把负号放进去
            if (negative) {
                buf[--charPos] = '-';
            }
//转换成字符串
            return StringLatin1.newString(buf, charPos, (33 - charPos));
        }
        return toStringUTF16(i, radix);
    }

toUnsignedString0(int val, int shift)

签名private static String toUnsignedString0(int val, int shift) 是私有的:D
参数
i:十进制正整数
shift:radix = 1 << shift;
主要代码

    private static String toUnsignedString0(int val, int shift) {
        // assert shift > 0 && shift <=5 : "Illegal shift value";
//numberOfLeadingZeros 返回高位的0的数目
//mag 即实际的位数
        int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
//chars 为转换后的字符串的实际位数。运算作用是为了补齐空位,防止实际位数少1
        int chars = Math.max(((mag + (shift - 1)) / shift), 1);
        if (COMPACT_STRINGS) {
            byte[] buf = new byte[chars];
            formatUnsignedInt(val, shift, buf, chars);
            return new String(buf, LATIN1);
        } else {
            byte[] buf = new byte[chars * 2];
            formatUnsignedIntUTF16(val, shift, buf, chars);
            return new String(buf, UTF16);
        }
    }
    
//用位运算来代替除法运算
    private static void formatUnsignedInt(int val, int shift, byte[] buf, int len) {
        int charPos = len;
        int radix = 1 << shift;
        int mask = radix - 1;
        do {
            buf[--charPos] = (byte)Integer.digits[val & mask];
            val >>>= shift;
        } while (charPos > 0);
    }

numberOfLeadingZeros(int i)

签名public static int numberOfLeadingZeros(int i)
功能:返回i高位的0的数目
说明:用了二分法,感觉非常巧妙。很美:D
相关函数numberOfTrailingZeros(int i),也用了二分法
主要代码

    public static int numberOfLeadingZeros(int i) {
        // HD, Count leading 0's
        if (i <= 0)
            return i == 0 ? 32 : 0;
        int n = 31;
        if (i >= 1 << 16) { n -= 16; i >>>= 16; }
        if (i >= 1 <<  8) { n -=  8; i >>>=  8; }
        if (i >= 1 <<  4) { n -=  4; i >>>=  4; }
        if (i >= 1 <<  2) { n -=  2; i >>>=  2; }
        return n - (i >>> 1);
    }

解析字符串

parseInt

签名public static int parseInt(CharSequence s, int beginIndex, int endIndex, int radix) throws NumberFormatException
参数
CharSequence s: 字符数组
int beginIndex: 开始下标
int endIndex: 结束下标
int radix: 进制
相关方法

public static int parseInt(String s, int radix)
public static int parseInt(String s) //十进制

//判断,如果是能确保不会是负数的话调用parseInt(String s, int radix) 
//len <= 5 || // 最大值在最大的进制下是6位,所以小于等于5位可以不考虑符号
//(radix == 10 && len <= 9)) { //十进制最多10位
//否则调用parseLong,这样就不需要考虑符号,只需要直接转换成数字就行了,最后才强转成int
public static int parseUnsignedInt(String s, int radix) 
public static int parseUnsignedInt(CharSequence s, int beginIndex, int endIndex, int radix)

问题
1. CharSequence是什么?
说明
主要代码:代码好长,想看自己去看看,我写写思路就好了,不想贴了。

//..验证输入合法性..

boolean negative = false;//负数
int i = beginIndex;
int limit = -Integer.MAX_VALUE;
//....
if (firstChar < '0') {//判断首位是数字还是'+''-' 
//如果不是'+''-',则抛出异常
i++;
if (i == endIndex) { 
//如果只有加减号,抛出异常
//如果结果超过最大值,则抛出异常
//接下来正常按位运算过去就好了
//他这里都先采用负数运算,正数则到最后才取反

valueOf(int i)

签名public static Integer valueOf(int i)
说明:这里用到了静态私有内部类IntegerCache,这里主要是放缓存的,预先缓存了一部分数字。会首先检查缓存池中是否已经有所需的值,没有才重新创建。
主要代码

public static Integer valueOf(int i) {
  if (i >= IntegerCache.low && i <= IntegerCache.high)
    return IntegerCache.cache[i + (-IntegerCache.low)];
  return new Integer(i);
}

IntegerCache缓存池

属性

static final int low = -128;

static final int high; //默认127
//可以通过 JVM 的启动参数 -XX:AutoBoxCacheMax=size 修改

static final Integer[] cache;//存有low到high的所有值

static Integer[] archivedCache;
//如果已经有了archivedCache,则直接赋值给cache,否则就是用for循环来初始化cache
posted @   sarise  阅读(74)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示