java.lang.*中Long 源代码详解

  • 核心方法
  • String toString(long i, int radix)
  • String toHexString(long i)
  • String toOctalString(long i)
  • String toBinaryString(long i)
  • String toString(long i)
  • long parseLong(String s, int radix)
  • Long valueOf(String s, int radix)
  • Long decode(String nm)
  • public Long(long value)
  • int hashCode(long value)
  • boolean equals(Object obj)
  • Long getLong(String nm)
  • int compare(long x, long y)

核心方法

public final class Long extends Number implements Comparable<Long> {

String toString(long i, int radix) 将long类型数值转为radix进制的字符串[OK]
String toHexString(long i) 将long类型数据转换成16进制形式的字符串[OK]
String toOctalString(long i) 将long类型数据转换成8进制形式的字符串[OK]
String toBinaryString(long i) 将long类型数据转换成2进制形式的字符串[OK]
String toString(long i) 获取long类型数值的字符串形式[OK]
long parseLong(String s, int radix) 将字符串按照radix进制,转化为long数值[OK]
Long valueOf(String s, int radix) 将字符串按照radix进制,转化为Long类型对象[OK]
Long decode(String nm) 将字符串转化为Long类型对象[OK]
public Long(long value) 构造函数[OK]
int hashCode(long value) 获取long类型的hashCode值[OK]
boolean equals(Object obj) 判断两个Long类型对象的值是否相等[OK]
Long getLong(String nm, long val) 从System.properties中获取Long对象[OK]
int compare(long x, long y) 比较两个long类型的数值

String toString(long i, int radix)

/**
  * 将long类型数值转为radix进制的字符串
  */
public static String toString(long i, int radix) {
	//判断当前进制是否在[2,36]范围内[0-9a-z]
    if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
        radix = 10;
    //如果当前进制为10,直接调用toString内部方法
    if (radix == 10)
        return toString(i);
    //long类型占用8个字节,一个字节占用8位
    //8*8 = 64
    //再加上符号位-、+,所以这char的长度为65    
    char[] buf = new char[65];
    //定义最后一个索引位置,根据进制原则
    //从右往左,位数一次递增
    int charPos = 64;
    //记录下符号位
    boolean negative = (i < 0);

    if (!negative) {//如果i>0,强制转为负数
        i = -i;
    }

	//如果i<=-radix
	//意味着,还可以继续转化进制
    while (i <= -radix) {
    	//(int)(-(i % radix)) 将i取余radix得到一个数字
    	//Integer.digits[i] 根据得到的数字,从digits进制表中查找对应字符
    	//buf[charPos--] = char 将上面查询到字符放到buf[charPos]位置,同时索引位置-1
        buf[charPos--] = Integer.digits[(int)(-(i % radix))];
        //将i / radix取整数
        i = i / radix;
    }
    //最后剩下的i<=-radix
    //将i转为整数,同时从digits进制表中查询对应的字符
    //将查询到的字符放到charPos当前位置
    buf[charPos] = Integer.digits[(int)(-i)];

    if (negative) {//如果确认是负数
    	//将charPos索引位置继续往前推一位,同时赋值上符号位
        buf[--charPos] = '-';
    }
	//调用String的构造方法,将char[]字符数组转为字符串
	//buf目标字符数组
	//charPos索引开始位置
	//(65-charPos) 截取的元素个数
    return new String(buf, charPos, (65 - charPos));
}

public static String toString(long i) {
	//如果发现i等于long的最小值
    if (i == Long.MIN_VALUE)
        return "-9223372036854775808";
    //获取i的字符串长度    
    int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
    //初始化字符数组的大小
    char[] buf = new char[size];
    //将i赋值到buf字符数组中
    getChars(i, size, buf);
    return new String(buf, true);
}

/**
  * 将long类型值,赋值给buf对象
  */
static void getChars(long i, int index, char[] buf) {
    long q;
    int r;
    //定义索引开始位置
    int charPos = index;
    //记录符号位
    char sign = 0;

    if (i < 0) {//如果i为负数,sign记录下符号位,同时将i转为正数
        sign = '-';
        i = -i;
    }

    // Get 2 digits/iteration using longs until quotient fits into an int
    while (i > Integer.MAX_VALUE) {
        q = i / 100;
        // really: r = i - (q * 100);
        r = (int)(i - ((q << 6) + (q << 5) + (q << 2)));
        i = q;
        buf[--charPos] = Integer.DigitOnes[r];
        buf[--charPos] = Integer.DigitTens[r];
    }

    // Get 2 digits/iteration using ints
    int q2;
    int i2 = (int)i;
    while (i2 >= 65536) {
        q2 = i2 / 100;
        // really: r = i2 - (q * 100);
        r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2));
        i2 = q2;
        buf[--charPos] = Integer.DigitOnes[r];
        buf[--charPos] = Integer.DigitTens[r];
    }

    // Fall thru to fast mode for smaller numbers
    // assert(i2 <= 65536, i2);
    for (;;) {
        q2 = (i2 * 52429) >>> (16+3);
        r = i2 - ((q2 << 3) + (q2 << 1));  // r = i2-(q2*10) ...
        buf[--charPos] = Integer.digits[r];
        i2 = q2;
        if (i2 == 0) break;
    }
    if (sign != 0) {
        buf[--charPos] = sign;
    }
}

String toHexString(long i)

/**
  * 将long类型数据转换成16进制形式的字符串
  */
public static String toHexString(long i) {
    return toUnsignedString0(i, 4);
}

static String toUnsignedString0(long val, int shift) {
    // assert shift > 0 && shift <=5 : "Illegal shift value";
    //下面两行代码,确定转化后的字符数组长度
    int mag = Long.SIZE - Long.numberOfLeadingZeros(val);
    int chars = Math.max(((mag + (shift - 1)) / shift), 1);
    char[] buf = new char[chars];

    formatUnsignedLong(val, shift, buf, 0, chars);
    return new String(buf, true);
}

/**
  * @param val 需要转化的val的值
  * @param shift 进制类型
  * @param buf 字符数组
  * @param offset 首位截取位置
  * @param len 截取长度
  */
static int formatUnsignedLong(long val, int shift, char[] buf, int offset, int len) {
    int charPos = len;
    //核心的地方shift决定进制类型
    int radix = 1 << shift;
    int mask = radix - 1;
    do {
    	//由于offset=0,所以可以理解成[buf--charPos]
    	//索引位置由高位往下递减
    	//((int) val) & mask 得到当前数值的的进制处理后的码表索引位置
    	//(10 & 15) 等于10,而码表10号位置刚好为a
        buf[offset + --charPos] = Integer.digits[((int) val) & mask];
        //无符号右移,相当于val/2
        val >>>= shift;
    } while (val != 0 && charPos > 0);
    //charPos是先用后减
	//一直到val ==0 或者charPos = 0结束循环
    return charPos;
}

String toOctalString(long i)

/**
  * 将long类型数据转换成8进制形式的字符串
  * 2^3 = 8
  */
public static String toOctalString(long i) {
    return toUnsignedString0(i, 3);
}

String toBinaryString(long i)

/**
  * 将long类型数据转换成2进制形式的字符串
  * 2^1 = 2
  */
public static String toBinaryString(long i) {
    return toUnsignedString0(i, 1);
}

String toString(long i)

/**
  * 获取long类型数值的字符串形式
  */
public static String toString(long i) {
	//如果i = long的最大值
    if (i == Long.MIN_VALUE)
        return "-9223372036854775808";
    //获取字符串最大长度,根据分析数据位,最长为19
    //外加符号位 stringSize(-i) + 1    
    int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
    char[] buf = new char[size];
    getChars(i, size, buf);
    return new String(buf, true);
}

// Requires positive x
//根据循环i次,在进行比较,决定x的位数
static int stringSize(long x) {
    long p = 10;
    for (int i=1; i<19; i++) {
        if (x < p)
            return i;
        p = 10*p;
    }
    return 19;
}

long parseLong(String s, int radix)

/**
  * 将字符串按照radix进制,转化为long数值
  * @param s 待转换的字符串
  * @param radix 字符串对应的进制数
  * //示例:Long.parseLong("201",8) -> 129
  * 核心代码处理:
  * digit = Character.digit(s.charAt(i++),radix);
  * result *= radix; 等价于 result = result * radix
  * result -= digit; 等价于 result = result - digit
  * 第一步:(将201,按照'2','0','1')分别取出
  * a.取出字符'2',result初始值为0
  * result = 0 * 8
  * result = 0 - 2
  * result = -2
  * 第二步:
  * b.取出字符'0'
  * result = -2 * 8
  * result = -16 - 0
  * result = -16
  * 第三步:
  * c.取出字符'1'
  * result = -16 * 8
  * result = -128 - 1
  * result = -129
  *
  * 最后根据符号位判断,将-129转化成129
  */
public static long parseLong(String s, int radix)
              throws NumberFormatException
{
    if (s == null) {//空检测
        throw new NumberFormatException("null");
    }
	//判断radix转化的进制是否在[2,36]的范围内
    if (radix < Character.MIN_RADIX) {
        throw new NumberFormatException("radix " + radix +
                                        " less than Character.MIN_RADIX");
    }
    if (radix > Character.MAX_RADIX) {
        throw new NumberFormatException("radix " + radix +
                                        " greater than Character.MAX_RADIX");
    }

    long result = 0;//用来接收最终结果
    boolean negative = false;//用来标记数据的正负性
    int i = 0, len = s.length();
    long limit = -Long.MAX_VALUE;
    long multmin;
    int digit;//记录索引对应字符的ASCII值

    if (len > 0) {
    	//取第一个字符,判断是否为字符
        char firstChar = s.charAt(0);
        //判断是否为数字
        if (firstChar < '0') { // Possible leading "+" or "-"		
        	//判断是否为负数
            if (firstChar == '-') {
            	//标记符号位
                negative = true;
                //如果是负数,设置limit的值为long的最小值
                limit = Long.MIN_VALUE;
            } else if (firstChar != '+')
            	//如果firstChar既不是数字字符
            	//也不是-符号,也不是+符号,则抛出异常
                throw NumberFormatException.forInputString(s);
			//在进行转换的时候,不能只是+、-符号,所以长度只为1则抛异常
            if (len == 1) // Cannot have lone "+" or "-"
                throw NumberFormatException.forInputString(s);
            //当满足所有条件,索引后移,读取数据位    
            i++;
        }
        //限制对应进制radix的最小值
        multmin = limit / radix;
        while (i < len) {//循环遍历字符串中的字符
            // Accumulating negatively avoids surprises near MAX_VALUE
            //在指定的基数radix,返回字符ch的数值
            digit = Character.digit(s.charAt(i++),radix);
            if (digit < 0) {//确保得到的基础是有效值
                throw NumberFormatException.forInputString(s);
            }
            if (result < multmin) {//确保最终结果不会超标
                throw NumberFormatException.forInputString(s);
            }

			//下面的代码是本方法的核心计算
			//遵循原则,根据读取到的位数,实时计算进制本身对应的值
			//最终转化为10进制数

            //result = result * radix
            result *= radix;
            if (result < limit + digit) {//确保最终结果不会超标
                throw NumberFormatException.forInputString(s);
            }
            //result = result - digit;
            result -= digit;
        }
    } else {
        throw NumberFormatException.forInputString(s);
    }
    //判断是否需要修改为负数
    return negative ? result : -result;
}

Long valueOf(String s, int radix)

/**
  * 将字符串按照radix进制,转化为long数值
  * @param s 待转换的字符串
  * @param radix 字符串对应的进制数
  */
public static Long valueOf(String s, int radix) throws NumberFormatException {
    return Long.valueOf(parseLong(s, radix));
}

Long decode(String nm)

/**
  * 将字符串转化为Long类型对象
  * decode方法不同于parseLong方法,虽然都是按照进制转化成具体long类型数值
  * 但是decode只支持16进制、8进制、2进制的格式转换
  * 而parseLong可以支持[2-32]中间任意进制的格式转换
  * 优化建议:
  * if (nm == null) {//空检测
        throw new NumberFormatException("null");
    }
  */
public static Long decode(String nm) throws NumberFormatException {
	
	//设置默认的字符串的进制为10进制
    int radix = 10;
    //index记录有效数值的开始索引位置
    //一般需要去除进制位或者符号位
    int index = 0;
    //用来记录正负值类型
    boolean negative = false;
    //用来记录最终的结果
    Long result;
	//如果字符串长度为0,则抛出此异常,此处可能发生空指针异常
    if (nm.length() == 0)
        throw new NumberFormatException("Zero length string");
    //获取第一个索引位置的字符
    char firstChar = nm.charAt(0);
    // Handle sign, if present
    //处理符号位,如果出现-、+,同时索引位置后移一位
    if (firstChar == '-') {
        negative = true;
        index++;
    } else if (firstChar == '+')
        index++;

    // Handle radix specifier, if present
    //判断如果目标字符串以0x或者0X(不区分大小)开头,则说明是16进制数
    //同时索引位置后移两位
    if (nm.startsWith("0x", index) || nm.startsWith("0X", index)) {
        index += 2;
        radix = 16;
    }
    //如果字符串以#开头(注意此时index可能已经后移),则说明也是16进制数据,索引位置后移一位即可,所以-#16、+#16也是合法的数值
    else if (nm.startsWith("#", index)) {
        index ++;
        radix = 16;
    }
    //如果nm是以0开头,且0后面还有字符,则按照8进制处理
    //Long.decode("0")是按照10进制进行转化的
    //而Long.decode("00")则是按照8进制转化的
    //虽然两者最终结果都是0,但内部处理方式完全不同
    else if (nm.startsWith("0", index) && nm.length() > 1 + index) {
        index ++;
        radix = 8;
    }
	//如果在处理完上面逻辑后,字符串索引位置还出现了-、+等符号
	//则认为字符非法
    if (nm.startsWith("-", index) || nm.startsWith("+", index))
        throw new NumberFormatException("Sign character in wrong position");

    try {
    	//截取有效字符串,调用内部valueOf方法,得到Long对象
        result = Long.valueOf(nm.substring(index), radix);
        //最后加上符号位
        result = negative ? Long.valueOf(-result.longValue()) : result;
    } catch (NumberFormatException e) {
        // If number is Long.MIN_VALUE, we'll end up here. The next line
        // handles this case, and causes any genuine format error to be
        // rethrown.
        //异常处理
        String constant = negative ? ("-" + nm.substring(index))
                                   : nm.substring(index);
        result = Long.valueOf(constant, radix);
    }
    return result;
}

public Long(long value)

/**
  * 构造方法
  */
public Long(long value) {
    this.value = value;
}

public Long(String s) throws NumberFormatException {
	//调用parseLong 10进制转换的方法
    this.value = parseLong(s, 10);
}

int hashCode(long value)

/**
  * 获取long类型的hashCode值
  */
public static int hashCode(long value) {
	//value 无符号右移32位
	//value 取反 value 结果
    return (int)(value ^ (value >>> 32));
}

boolean equals(Object obj)

/**
  * 判断两个Long类型对象的值是否相等
  */
public boolean equals(Object obj) {
	//首先判断是否为Long类型对象
    if (obj instanceof Long) {
    	//再判断值是否相等
        return value == ((Long)obj).longValue();
    }
    return false;
}

Long getLong(String nm)

/**
  * @param nm 字符串
  * @param val 默认返回值
  */
public static Long getLong(String nm, Long val) {
    String v = null;
    try {
        v = System.getProperty(nm);
    } catch (IllegalArgumentException | NullPointerException e) {
    }
    if (v != null) {
    	//如果v存在,将v转换成Long对象
        try {
            return Long.decode(v);
        } catch (NumberFormatException e) {
        }
    }
    //默认返回val
    return val;
}

int compare(long x, long y)

/**
  * 比较两个Long类型对象的值
  * 如果x < y 返回 -1
  * 如果x == y 返回0
  * 如果x > y 返回1
  */
public int compareTo(Long anotherLong) {
    return compare(this.value, anotherLong.value);
}

public static int compare(long x, long y) {
    return (x < y) ? -1 : ((x == y) ? 0 : 1);
}