此次来看看Long
的源代码,基于 jdk1.8.0_181.jdk 版本,若有错误,欢迎联系指出。html
Long
是long
基础数据类型的包装类,从源码的角度来看,总体的思路和Integer
是极其类似的,若是没有看过Integer
的源代码,建议能够看看 Java源码 - Integer 这篇文章,相关的思路已经说明清楚。这篇文章类似逻辑会引用原有的逻辑说明,不会再重复介绍了。java
public final class Long extends Number implements Comparable<Long> 复制代码
带有final
标识,也就是说不可继承的。另外继承了Number
类,而Number
类实现了Serializable
接口,因此Long
也是能够序列化的;实现了Comparable
接口。git
@Native public static final long MIN_VALUE = 0x8000000000000000L;
@Native public static final long MAX_VALUE = 0x7fffffffffffffffL;
复制代码
MIN_VALUE
表示了Long
最小值,对应为-2^63
MAX_VALUE
表示了Lone
最大值,对应为2^63 - 1
这里的两个常量都带有@Native
注解,表示这两个常量值字段能够被native代码引用。当native代码和Java代码都须要维护相同的变量时,若是Java代码使用了@Native
标记常量字段时,编译时能够生成对应的native代码的头文件。算法
public static final Class<Long> TYPE = (Class<Long>) Class.getPrimitiveClass("long");
复制代码
获取类信息,Long.TYPE == long.class
二者是等价的数组
@Native public static final int SIZE = 64;
复制代码
表示了Long
的bit数,64位。缓存
public static final int BYTES = SIZE / Byte.SIZE;
复制代码
表示了Long
的字节数,计算值固定为8oracle
private final long value;
复制代码
Long
是long
的包装类,这里存放了long
类型对应的数据值信息ide
@Native private static final long serialVersionUID = 4290774380558885855L;
复制代码
private static class LongCache {
private LongCache(){}
static final Long cache[] = new Long[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Long(i - 128);
}
}
复制代码
LongCache
是Long
的静态内部类,内部定义了一个长度为128+127+1=256
的数组,用于缓存经常使用的数字范围,避免后续使用时从新进行实例化,提高性能。函数
public Long(long value) {
this.value = value;
}
public Long(String s) throws NumberFormatException {
this.value = parseLong(s, 10);
}
复制代码
存在两个构造函数,支持传入long
和String
类型参数。但参数类型为String
时,内部以十进制格式调用了parseLong
方法进行处理实现。post
public static long parseLong(String s) throws NumberFormatException public static long parseLong(String s, int radix) throws NumberFormatException 复制代码
存在两个parseLong
方法,具体逻辑和Integer
的parseInt
相似,能够参考相关的文章介绍parseInt 方法
public static long parseUnsignedLong(String s) throws NumberFormatException {
return parseUnsignedLong(s, 10);
}
public static long parseUnsignedLong(String s, int radix) throws NumberFormatException 复制代码
存在两个parseUnsignedLong
方法,第一个方法内部默认以十进制调用了第二个方法进行实现,方法的总体逻辑与Integer
的parseUnsignedInt
基本一致,能够参考 parseUnsignedInt 方法
static void getChars(long i, int index, char[] buf) 复制代码
该方法主要的逻辑就是将输入long
类型数据转换成字符形式放入char数组中,不支持 Long.MIN_VALUE。具体逻辑说明能够参考Integer
的getChars 方法
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;
}
复制代码
获取对应数据的字符串长度,设定最大长度19进行循环判断(由于Long.MAX_VALUE
转换成十进制数,最大长度为19位);从逻辑能够看出,只支持正数,负数的结果是错误的。
public String toString() {
return toString(value);
}
public static String toString(long i) public static String toString(long i, int radix) 复制代码
存在三个toString
方法,其中两个为静态方法,与Integer
一致,能够参考toString 方法
Integer
的toUnsignedString
方法内部实现调用了Long
的toUnsignedString
方法进行实现,因此咱们来看看这个方法的实现。
public static String toUnsignedString(long i, int radix) {
if (i >= 0)
return toString(i, radix);
else {
switch (radix) {
case 2:
return toBinaryString(i);
case 4:
return toUnsignedString0(i, 2);
case 8:
return toOctalString(i);
case 10:
/* * We can get the effect of an unsigned division by 10 * on a long value by first shifting right, yielding a * positive value, and then dividing by 5. This * allows the last digit and preceding digits to be * isolated more quickly than by an initial conversion * to BigInteger. */
long quot = (i >>> 1) / 5;
long rem = i - quot * 10;
return toString(quot) + rem;
case 16:
return toHexString(i);
case 32:
return toUnsignedString0(i, 5);
default:
return toUnsignedBigInteger(i).toString(radix);
}
}
}
复制代码
把long
类型数值转换成对应的无符号字符串。由于long
的最大值为2^63 - 1
,正数的值转换成无符号数时依旧在这个范围内,因此直接调用toString
方法实现。对于负数而言,根据进制的不同,调用不一样的方法进行处理。
public static String toHexString(long i) {
return toUnsignedString0(i, 4);
}
public static String toOctalString(long i) {
return toUnsignedString0(i, 3);
}
public static String toBinaryString(long i) {
return toUnsignedString0(i, 1);
}
复制代码
这三个方法的内部实现均是调用了toUnsignedString0
方法,咱们来看下toUnsignedString0
的代码实现
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);
}
复制代码
咱们来分析一下这几行代码:
int mag = Long.SIZE - Long.numberOfLeadingZeros(val);
复制代码
mag
表示了该数字表示为二进制实际须要的位数(去除高位的0)。numberOfLeadingZeros
方法就是获取该数字二进制格式下最高位1前面的0的个数。
int chars = Math.max(((mag + (shift - 1)) / shift), 1);
复制代码
根据mag
和shift
获取转换成对应进制的字符串所需的字符数(shift
表明了进制数)。
char[] buf = new char[chars];
formatUnsignedLong(val, shift, buf, 0, chars);
复制代码
将转换的字符写入到buf
数组中,来看下formatUnsignedLong
方法实现。
static int formatUnsignedLong(long val, int shift, char[] buf, int offset, int len) {
int charPos = len;
// 获取进制
int radix = 1 << shift;
// 掩码,二进制都为1
int mask = radix - 1;
do {
// 去除对应进制范围内的最后一位数,获取对应的字符
buf[offset + --charPos] = Integer.digits[((int) val) & mask];
// 无符号右移,去除上一步已经处理的值
val >>>= shift;
} while (val != 0 && charPos > 0);
return charPos;
}
复制代码
总体思路就是这样,这样就获取到了对应的字符数组,而后转换成字符串输出结果。
private static BigInteger toUnsignedBigInteger(long i) {
if (i >= 0L)
return BigInteger.valueOf(i);
else {
int upper = (int) (i >>> 32);
int lower = (int) i;
// return (upper << 32) + lower
return (BigInteger.valueOf(Integer.toUnsignedLong(upper))).shiftLeft(32).
add(BigInteger.valueOf(Integer.toUnsignedLong(lower)));
}
}
复制代码
将long
类型值转换成BigInteger
类型值,当参数>=0
时,使用BigInteger.valueOf(i)
方法处理返回结果;若是小于0,则先拆分按照高位4字节和低位4字节进行处理,而后获取结果。
public static Long valueOf(String s, int radix) throws NumberFormatException {
return Long.valueOf(parseLong(s, radix));
}
public static Long valueOf(String s) throws NumberFormatException {
return Long.valueOf(parseLong(s, 10));
}
public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}
复制代码
存在三个valueOf
方法,前两个内部实现均是调用了第三个方法。当参数在-128~127
之间时,从LongCache
的缓存数组中获取,不然从新实例化对象返回。因此能够看看下面的示例:
Long a = Long.valueOf(108);
Long b = Long.valueOf(108);
Long c = Long.valueOf(1108);
Long d = Long.valueOf(1108);
System.out.println(a == b); // true
System.out.println(c == d); // false
复制代码
public static Long decode(String nm) throws NumberFormatException 复制代码
将对应的字符串转换成整数,支持十进制,0x, 0X, #
开头的十六进制数,0
开头的八进制数。代码逻辑解释能够参考 Integer 的 decode 方法
public static Long getLong(String nm) {
return getLong(nm, null);
}
public static Long getLong(String nm, long val) {
Long result = Long.getLong(nm, null);
return (result == null) ? Long.valueOf(val) : result;
}
public static Long getLong(String nm, Long val) {
String v = null;
try {
v = System.getProperty(nm);
} catch (IllegalArgumentException | NullPointerException e) {
}
if (v != null) {
try {
return Long.decode(v);
} catch (NumberFormatException e) {
}
}
return val;
}
复制代码
三个getLong
方法,主要是最后一个方法。传入一个配置的key以及默认值,获取对应的系统配置值,若为空或者为null,返回对应的默认值
public byte byteValue() {
return (byte)value;
}
public short shortValue() {
return (short)value;
}
public int intValue() {
return (int)value;
}
public long longValue() {
return value;
}
public float floatValue() {
return (float)value;
}
public double doubleValue() {
return (double)value;
}
复制代码
直接进行强制类型转换,返回对应的结果
public int hashCode() {
return Long.hashCode(value);
}
public static int hashCode(long value) {
return (int)(value ^ (value >>> 32));
}
复制代码
hashCode
返回int
类型结果,首先将输入参数无符号右移32位,而后与原来的值进行异或运算,强制转换成int
类型返回对应的结果。
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}
复制代码
首先判断是否是Long
对象的实例,而后比较二者的值是否相等;这里能够看出咱们无需担忧输入参数为null
的时候会出现报错的状况。
public static int compare(long x, long y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
复制代码
比较两个参数的值,三元表达式,x < y
时返回-1
,x == y
时返回0
,x > y
时返回1
public int compareTo(Long anotherLong) {
return compare(this.value, anotherLong.value);
}
复制代码
调用compare
方法比较两个值,返回结果与compare
方法一致
public static int compareUnsigned(long x, long y) {
return compare(x + MIN_VALUE, y + MIN_VALUE);
}
复制代码
两个输入参数看成无符号整数进行比较,这里经过加上MIN_VALUE
确保在范围内。有个小技巧,-1加上MIN_VALUE
后会变成最大正数。
public static long divideUnsigned(long dividend, long divisor) {
if (divisor < 0L) { // signed comparison
// Answer must be 0 or 1 depending on relative magnitude
// of dividend and divisor.
return (compareUnsigned(dividend, divisor)) < 0 ? 0L :1L;
}
if (dividend > 0) // Both inputs non-negative
return dividend/divisor;
else {
/* * For simple code, leveraging BigInteger. Longer and faster * code written directly in terms of operations on longs is * possible; see "Hacker's Delight" for divide and remainder * algorithms. */
return toUnsignedBigInteger(dividend).
divide(toUnsignedBigInteger(divisor)).longValue();
}
}
复制代码
无符号除法,输入参数转换成无符号数相除获取结果
compareUnsigned
比较除数和被除数,被除数 < 除数时返回0,不然返回1(取决于被除数的正负性)toUnsignedBigInteger
转换成无符号BigInteger
进行运算获取对应的结果public static long remainderUnsigned(long dividend, long divisor) {
if (dividend > 0 && divisor > 0) { // signed comparisons
return dividend % divisor;
} else {
if (compareUnsigned(dividend, divisor) < 0) // Avoid explicit check for 0 divisor
return dividend;
else
return toUnsignedBigInteger(dividend).
remainder(toUnsignedBigInteger(divisor)).longValue();
}
}
复制代码
无符号取余,输入参数转换成无符号数进行取余获取结果。
toUnsignedBigInteger
方法,二者均转换成无符号BigInteger
进行运算获取对应的结果public static long highestOneBit(long i) {
// HD, Figure 3-1
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
i |= (i >> 32);
return i - (i >>> 1);
}
复制代码
获取最高位为1,其他为0的long
类型值。经过位移或逻辑,将最高位右边1位设为1,而后2倍增加左移或操做,1的位数不断增长,最后1+2+4+8+16+32=63,能够确保覆盖全部可能性。而后使用i - (i >>> 1)
保留最高位1返回结果。
public static long lowestOneBit(long i) {
// HD, Section 2-1
return i & -i;
}
复制代码
获取最低位1,其他位为0的值。负数以正数的补码表示,对整数的二进制进行取反码而后加1,获得的结果与输入二进制进行与操做,结果就是最低位1保留,其余位为0。
public static int numberOfLeadingZeros(long i) {
// HD, Figure 5-6
if (i == 0)
return 64;
int n = 1;
int x = (int)(i >>> 32);
if (x == 0) { n += 32; x = (int)i; }
if (x >>> 16 == 0) { n += 16; x <<= 16; }
if (x >>> 24 == 0) { n += 8; x <<= 8; }
if (x >>> 28 == 0) { n += 4; x <<= 4; }
if (x >>> 30 == 0) { n += 2; x <<= 2; }
n -= x >>> 31;
return n;
}
复制代码
判断二进制格式下,最高位的1左边存在多少个0。这里使用了相似二分查找的思想,经过左右移位的操做一步步缩小1所在的bit位置范围,最后经过简单计算获取0的个数。开始增长了对特殊值0的判断。能够查看numberOfLeadingZeros 方法中的例子加深了解
public static int numberOfTrailingZeros(long i) {
// HD, Figure 5-14
int x, y;
if (i == 0) return 64;
int n = 63;
y = (int)i; if (y != 0) { n = n -32; x = y; } else x = (int)(i>>>32);
y = x <<16; if (y != 0) { n = n -16; x = y; }
y = x << 8; if (y != 0) { n = n - 8; x = y; }
y = x << 4; if (y != 0) { n = n - 4; x = y; }
y = x << 2; if (y != 0) { n = n - 2; x = y; }
return n - ((x << 1) >>> 31);
}
复制代码
与上面的numberOfLeadingZeros
方法对应,获取二进制格式下尾部的0的个数。
public static int bitCount(long i) {
// HD, Figure 5-14
i = i - ((i >>> 1) & 0x5555555555555555L);
i = (i & 0x3333333333333333L) + ((i >>> 2) & 0x3333333333333333L);
i = (i + (i >>> 4)) & 0x0f0f0f0f0f0f0f0fL;
i = i + (i >>> 8);
i = i + (i >>> 16);
i = i + (i >>> 32);
return (int)i & 0x7f;
}
复制代码
统计二进制格式下1的数量。代码第一眼看着是懵的,都是位运算,实际里面实现的算法逻辑仍是很巧妙的,着实佩服,这里就不介绍了,感兴趣的能够看下Integer 的 bitCount 方法介绍,了解其中的运算逻辑
public static long rotateLeft(long i, int distance) {
return (i << distance) | (i >>> -distance);
}
public static long rotateRight(long i, int distance) {
return (i >>> distance) | (i << -distance);
}
复制代码
旋转二进制,rotateLeft
将特定位数的高位bit放置低位,返回对应的数值;rotateRight
将特定位数的低位bit放置高位,返回对应的数值。当distance
是负数的时候,rotateLeft(val, -distance) == rotateRight(val, distance)
以及rotateRight(val, -distance) == rotateLeft(val, distance)
。另外,当distance
是64的任意倍数时,实际是没有效果的 ,至关于无操做。
这里须要说一下(i >>> -distance)
,diatance
为正数时,右移一个负数逻辑至关于i >>> 64+(-distance)
public static long reverse(long i) {
// HD, Figure 7-1
i = (i & 0x5555555555555555L) << 1 | (i >>> 1) & 0x5555555555555555L;
i = (i & 0x3333333333333333L) << 2 | (i >>> 2) & 0x3333333333333333L;
i = (i & 0x0f0f0f0f0f0f0f0fL) << 4 | (i >>> 4) & 0x0f0f0f0f0f0f0f0fL;
i = (i & 0x00ff00ff00ff00ffL) << 8 | (i >>> 8) & 0x00ff00ff00ff00ffL;
i = (i << 48) | ((i & 0xffff0000L) << 16) |
((i >>> 16) & 0xffff0000L) | (i >>> 48);
return i;
}
复制代码
看着是否是和bitCount
有点相似,其实核心逻辑类似。先是交换相邻1位bit的顺序,再交换相邻2位bit顺序,再继续交换相邻4位bit顺序,而后交换相邻8位bit顺序,再交换中间32位bit的顺序,最后最高16位再和低16位进行交换就完成了整个过程,全程位运算甚是奇妙。
public static int signum(long i) {
// HD, Section 2-7
return (int) ((i >> 63) | (-i >>> 63));
}
复制代码
获取符号数,若为负数,返回-1;若为0则返回0;为正数,则返回1。
public static long reverseBytes(long i) {
i = (i & 0x00ff00ff00ff00ffL) << 8 | (i >>> 8) & 0x00ff00ff00ff00ffL;
return (i << 48) | ((i & 0xffff0000L) << 16) |
((i >>> 16) & 0xffff0000L) | (i >>> 48);
}
复制代码
按照输入参数二进制格式,以字节为单位进行翻转,返回对应的结果数值。
(i & 0x00ff00ff00ff00ffL) << 8 | (i >>> 8) & 0x00ff00ff00ff00ffL
交换相邻字节顺序(i >>> 48) | (i << 48)
交换最高16位和最低16位bit位置。((i >>> 16) & 0xffff0000L) | ((i & 0xffff0000L) << 16)
交换中间32位bit位置public static long sum(long a, long b) {
return a + b;
}
public static long max(long a, long b) {
return Math.max(a, b);
}
public static long min(long a, long b) {
return Math.min(a, b);
}
复制代码
这个就不说了,很简单的方法。
由于long
是64bit,须要注意下long
的原子性逻辑,这里是官方文档的具体说明Non-Atomic Treatment of double
and long
,相关解释说明能够参考 double文章中的详细说明。
总的代码逻辑来看,Long
和Integer
的方法基本一致,方法内的实现也基本一致,若是了解了Integer
的相关逻辑,Long
相关代码能够快速的过一下便可;另外值得注意的是long
的原子性问题。