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);
}
















