目录
  1. 1. Long源码解析
    1. 1.1. 类定义
    2. 1.2. 主要变量
    3. 1.3. 内部类
    4. 1.4. 构造方法
    5. 1.5. 主要方法
      1. 1.5.1. toString
        1. 1.5.1.1. 无符号转换String
      2. 1.5.2. hashCode
      3. 1.5.3. equals
      4. 1.5.4. getChars
      5. 1.5.5. 自动拆箱 xxxValue
      6. 1.5.6. 自动装箱valueOf
      7. 1.5.7. 格式化字符串为long
      8. 1.5.8. decode
      9. 1.5.9. getLong
      10. 1.5.10. compareTo
      11. 1.5.11. 数学运算方法
      12. 1.5.12. 位运算
Long源码解析

Long源码解析

类定义

1
public final class Long extends Number implements Comparable<Long>
  • Long被final修饰的,不可以被继承(由于被final修饰)
  • 继承于Number类(该类继承了Serializable序列化接口),需要重写各种xxxValue方法,xxxValue方法就是转换成对应的类型。Number类是java.lang包下的一个抽象类,提供了将包装类型拆箱成基本类型的方法,所有基本类型的包装类型都继承了该抽象类
  • Long实现了比较接口(需要重写compareTo方法)

主要变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 保持 long 类型的最小值的常量,该值为 -2的63方
public static final long MIN_VALUE = 0x8000000000000000L;

// 保持 long 类型的最大值的常量,该值为 2的63方-1
public static final long MAX_VALUE = 0x7fffffffffffffffL;

// TYPE的toString的值是long.
Class的getPrimitiveClass是一个native方法,在Class.c中有个Java_java_lang_Class_getPrimitiveClass方法与之对应,所以JVM层面会通过JVM_FindPrimitiveClass函数根据"long"字符串获得jclass,最终到Java层则为Class<Long>
public static final Class<Long> TYPE = (Class<Long>) Class.getPrimitiveClass("long");

// Long对应的基础类型long值
private final long value;

// SIZE用来表示二进制补码形式的long值的比特数,值为64,静态变量且不可变
@Native public static final int SIZE = 64;

// BYTES用来表示二进制补码形式的long值的字节数,值为SIZE除于Byte.SIZE,结果为8
public static final int BYTES = SIZE / Byte.SIZE;

内部类

使用亨元模式,来减少对象的创建

1
2
3
4
5
6
7
8
9
10
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的一个内部类,它包含了long可能值的Long数组,默认范围是[-128,127],它不会像Byte类将所有可能值缓存起来,因为long类型范围很大,将它们全部缓存起来代价太高,而Byte类型就是从-128到127,一共才256个.这里默认只实例化256个Long对象,当Long的值范围在[-128,127]时则直接从缓存中获取对应的Long对象,不必重新实例化.这些缓存值都是静态且final的,避免重复的实例化和回收

构造方法

1
2
3
4
5
6
7
public Long(long value) {
this.value = value;
}

public Long(String s) throws NumberFormatException {
this.value = parseLong(s, 10);
}

分别可以传入long和String类型.它是通过调用parseLong方法进行转换的,所以转换逻辑与上面的parseLong方法一样

主要方法

toString

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public String toString() {
return toString(value);
}

/**
* 返回当前long的字符串形式
* @param i
* @return String
*/
public static String toString(long i) {
if (i == Long.MIN_VALUE)
return "-9223372036854775808";
// 判断是否为负数,计算长度
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
// 将数字分成一个个char,保存到buf数组中
getChars(i, size, buf);
return new String(buf, true);
}

// 得出long型对应的数字位数
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;
}

/**
* 转化对应进制的数字为十进制
* @param i 要转换为字符串的 long
* @param radix 进制数
* @return String
*/
public static String toString(long i, int radix) {
// 如果进制数小于2进制 或者大于 26进制,则改用十进制。
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
radix = 10;
/* 如果是十进制,用最快的版本 */
if (radix == 10)
return toString(i);
// 创建一个65位的字符数组(负数时:1位符号位+64位数字;正数时,64位数字)
char[] buf = new char[65];
int charPos = 64;
boolean negative = (i < 0);
// 将正数转为负数进行运算,防止负数转为正数的溢出情况
if (!negative) {
i = -i;
}
// 循环判断当前转换的字符是否小于计数的相反数
while (i <= -radix) {
//根据余数的相反数在digits数组中获取相应的字符,倒序存放到buf[]数组里
buf[charPos--] = Integer.digits[(int)(-(i % radix))];
i = i / radix;
}
buf[charPos] = Integer.digits[(int)(-i)];
// 若是负数,加减号
if (negative) {
buf[--charPos] = '-';
}
// 返回一个字符串,参数为char数组、起始位置、字符长度
return new String(buf, charPos, (65 - charPos));
}

无符号转换String

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// 默认十进制无符号
public static String toUnsignedString(long i) {
return toUnsignedString(i, 10);
}

/**
* 返回当前long类型的i的shift进制的字符串形式的私有工具类
* 对于大于0的long值直接用toString转换,而小于0的则要按照进制不同分别做不同处理
* @param i
* @param shift 进制数
* @return String
*/
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:
/*
* 我们可以通过右移得到一个正的值,然后除以5来得到一个长值的
* 无符号除10的效果。这使得最后一位数和前一位数之间的隔离比
* 初始转换为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的2进制的字符串形式
* @param i 要转换为字符串的 long
* @return String
*/
public static String toBinaryString(long i) {
return toUnsignedString0(i, 1);
}

/**
* 格式化当前long的2进制到字符串形式
* 先计算转换成对应进制需要的字符数,然后再通过formatUnsignedInt方法来填充字符数组,该方法做的事情就是使用进制之间的转换方法来获取对应的字符
* @param i 要转换为字符串的 long
* @return String
*/
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);
}

static int formatUnsignedLong(long val, int shift, char[] buf, int offset, int len) {
int charPos = len;
int radix = 1 << shift;
int mask = radix - 1;
do {
buf[offset + --charPos] = Integer.digits[((int) val) & mask];
val >>>= shift;
} while (val != 0 && charPos > 0);

return charPos;
}

/**
* 返回当前long的8进制的字符串形式
* @param i 要转换为字符串的 long
* @return String
*/
public static String toOctalString(long i) {
return toUnsignedString0(i, 3);
}

/**
* 返回当前long的16进制的字符串形式
* @param i 要转换为字符串的 long
* @return String
*/
public static String toHexString(long i) {
return toUnsignedString0(i, 4);
}

/**
* long转成BigInteger类型,大于0用BigInteger.valueOf进行转换,如果小于0则需要先转成高4字节和低4字节,然后再转换
* @param i 要转换为字符串的 long
* @return BigInteger
*/
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)));
}
}

hashCode

1
2
3
4
5
6
7
public int hashCode() {
return Long.hashCode(value);
}

public static int hashCode(long value) {
return (int)(value ^ (value >>> 32));
}

可以看到hashCode方法返回的事int类型,首先将long型值无符号右移32位,再和原来的值进行异或运算,最后返回int类型值

equals

1
2
3
4
5
6
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}

比较是否相同时先判断是不是Long类型再比较值

getChars

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/**
* 该方法主要做的是将某个long型数值放到char数组里面。如把357按顺序放到char数组
*/
static void getChars(long i, int index, char[] buf) {
long q;
int r;
int charPos = index;
char sign = 0;

if (i < 0) {
sign = '-';
i = -i;
}

// 将long拆成高位4个字节和低位4个字节处理分开处理,while (i >= Integer.MAX_VALUE)部分就是处理高位的4个字节
while (i > Integer.MAX_VALUE) {
q = i / 100;
// really: r = i - (q * 100);
// ((q << 6) + (q << 5) + (q << 2))其实等于q*100,用来获取十位和个位
r = (int)(i - ((q << 6) + (q << 5) + (q << 2)));
i = q;
// 每次处理2位数
buf[--charPos] = Integer.DigitOnes[r];
buf[--charPos] = Integer.DigitTens[r];
}

// 处理低4个字节,继续将4个字节分为高位2个字节和低位2个字节
int q2;
int i2 = (int)i;
// while (i >= 65536)部分就是处理高位的两个字节,每次处理2位数,处理逻辑与高位4个字节的处理逻辑一样
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];
}

// 低位的两个字节,本质也是求余思想,但又用了一些技巧
// assert(i2 <= 65536, i2);
for (;;) {
// (i * 52429) >>> (16+3)其实约等于i/10
q2 = (i2 * 52429) >>> (16+3);
// r = i2-(q2*10) ...
r = i2 - ((q2 << 3) + (q2 << 1));
// 再通过Integer.digits数组获取到对应的字符
buf[--charPos] = Integer.digits[r];
i2 = q2;
if (i2 == 0) break;
}
// 可以看到低位处理时它尽量避开了除法,取而代之的是用乘法和右移来实现,可见除法是一个比较耗时的操作,比起乘法和移位。
// 另外也可以看到能用移位和加法来实现乘法的地方也尽量不用乘法,这也说明乘法比起它们更加耗时。
// 而高位处理时没有用移位是因为做乘法后可能会溢出


if (sign != 0) {
buf[--charPos] = sign;
}
}

自动拆箱 xxxValue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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;
}

包括shortValue、intValue、longValue、byteValue、floatValue和doubleValue等方法,其实就是转换成对应的类型

自动装箱valueOf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 核心逻辑在第一个valueOf方法中,因为LongCache缓存了[-128,127]值的Long对象,对于在范围内的直接从LongCache的数组中获取对应的Long对象即可,而在范围外的则需要重新实例化了
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);
}

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

格式化字符串为long

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
public static long parseLong(String s) throws NumberFormatException {
return parseLong(s, 10);
}

/**
* @param s: 待转换字符串
* @param radix: 对应的进制数
* 如Long.parseLong("100",10)表示十进制的100,所以值为100;而Long.parseLong("100",2)表示二进制的100,所以值为4.另外如果Long.parseLong("10000000000000000000",10)会抛出java.lang.NumberFormatException异常
*/
public static long parseLong(String s, int radix) throws NumberFormatException {
// 判断字符串不为空
if (s == null) {
throw new NumberFormatException("null");
}

// 进制数在Character.MIN_RADIX和Character.MAX_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;

// 判断输入的字符串的长度必须大于0
if (len > 0) {
char firstChar = s.charAt(0);
// 第一个字符可能为数字或负号或正号进行处理
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Long.MIN_VALUE;
} else if (firstChar != '+')
throw NumberFormatException.forInputString(s);

if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}

/**
* 核心处理逻辑是字符串转换数字,n进制转成十进制办法基本大家都知道的:
* 1. 假如357为8进制,则结果为3*8^2+5*8^1+7*8^0 = 239
* 2. 假如357为十进制,则结果为3*10^2+5*10^1+7*10^0 = 357
* 上面的转换方法也差不多是根据此方法,只是稍微转变了思路:
* 方式分别为((3*8+5)*8+7) = 239和((3*10+5)*10+7)=357
* 从中可以推出规则了,从左到右遍历字符串的每个字符,然后乘以进制数,再加上下一个字符,接着再乘以进制数,再加上下个字符,不断重复,直到最后一个字符
* 除此之外另外一个不同就是上面的转换不使用加法来做,全都转成负数来运算,其实可以看成是等价了,这个很好理解,而为什么要这么做就要归咎到long类型的范围了,因为负数Long.MIN_VALUE变化为正数时会导致数值溢出,所以全部都用负数来运算
*/
multmin = limit / radix;
while (i < len) {
// 负积累可避免MAX_VALUE溢出
digit = Character.digit(s.charAt(i++),radix);
if (digit < 0) {
throw NumberFormatException.forInputString(s);
}
if (result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
result -= digit;
}
} else {
throw NumberFormatException.forInputString(s);
}
return negative ? result : -result;
}

public static long parseUnsignedLong(String s) throws NumberFormatException {
return parseUnsignedLong(s, 10);
}

public static long parseUnsignedLong(String s, int radix)
throws NumberFormatException {
if (s == null) {
throw new NumberFormatException("null");
}

int len = s.length();
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar == '-') {
throw new NumberFormatException(String.format("Illegal leading minus sign " + "on unsigned string %s.", s));
} else {
// Long.MAX_VALUE在Character.MAX_RADIX是13位
// Long.MAX_VALUE in base 10 is 19 digits
if (len <= 12 || (radix == 10 && len <= 18) ) {
return parseLong(s, radix);
}

// 上述进行len检查,因此无需对len进行范围检查.
long first = parseLong(s.substring(0, len - 1), radix);
int second = Character.digit(s.charAt(len - 1), radix);
if (second < 0) {
throw new NumberFormatException("Bad digit at end of " + s);
}
long result = first * radix + second;
if (compareUnsigned(result, first) < 0) {
/*
* 最大无符号值(2 ^ 64)-1比最大有符号值(2 ^ 63)-1多花一个位数来表示.
* 因此解析(len-1)位将在签名解析的范围内.换句话说,如果解析(len -1)位溢出签名解析,则解析len位肯定会溢出未签名解析.
* 上面的compareUnsigned检查可发现出现无符号溢出并合并了最后一位数字的情况
*/
throw new NumberFormatException(String.format("String value %s exceeds " + "range of unsigned long.", s));
}
return result;
}
} else {
throw NumberFormatException.forInputString(s);
}
}

decode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public static Long decode(String nm) throws NumberFormatException {
int radix = 10;
int index = 0;
boolean negative = false;
Long result;

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
if (nm.startsWith("0x", index) || nm.startsWith("0X", index)) {
index += 2;
radix = 16;
}
else if (nm.startsWith("#", index)) {
index ++;
radix = 16;
}
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 {
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;
}

decode方法主要作用是解码字符串转成Long型,比如Long.decode(“11”)的结果为11;Long.decode(“0x11”)和Long.decode(“#11”)结果都为17,因为0x和#开头的会被处理成十六进制;Long.decode(“011”)结果为9,因为0开头会被处理成8进制

getLong

从系统变量中获取Long值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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;
}

compareTo

1
2
3
4
5
6
7
8
9
10
11
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);
}

public static int compareUnsigned(long x, long y) {
return compare(x + MIN_VALUE, y + MIN_VALUE);
}

数学运算方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// 除法运算
public static long divideUnsigned(long dividend, long divisor) {
// 除数小于0
if (divisor < 0L) {
// 签名比较,结果必须为0或1,具体取决于被除数和除数的相对大小
return (compareUnsigned(dividend, divisor)) < 0 ? 0L :1L;
}
// 被除数大于0
if (dividend > 0)
return dividend/divisor;
else {
// 对于简单值,使用biginger.直接以long操作的方式编写更长更快的代码是可以的
return toUnsignedBigInteger(dividend).
divide(toUnsignedBigInteger(divisor)).longValue();
}
}

// 余数运算
public static long remainderUnsigned(long dividend, long divisor) {
// 有符号比较
if (dividend > 0 && divisor > 0) {
return dividend % divisor;
} else {
// 避免对0除数的显式检查
if (compareUnsigned(dividend, divisor) < 0)
return dividend;
else
return toUnsignedBigInteger(dividend).
remainder(toUnsignedBigInteger(divisor)).longValue();
}
}

// 加法运算
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);
}

位运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/**
* 该方法返回i的二进制中最高位的1,其他全为0的值
* 比如i=10时,二进制即为1010,最高位的1,其他为0,则是1000
* 如果i=0,则返回0.如果i为负数则固定返回-2147483648,因为负数的最高位一定是1,即有1000,0000,0000,0000,0000,0000,0000,0000
* 这一堆移位操作是什么意思: 将i右移一位再或操作,则最高位1的右边也为1了,接着再右移两位并或操作,则右边1+2=3位都为1了,接着1+2+4=7位都为1,直到1+2+4+8+16+32=63都为1,最后用i - (i >>> 1)自然得到最终结果
*/
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);
}

/**
* 与highestOneBit方法对应,lowestOneBit获取最低位1,其他全为0的值
* 这个操作较简单:先取负数,这个过程需要对正数的i取反码然后再加1,得到的结果和i进行与操作,刚好就是最低位1其他为0的值了
*/
public static long lowestOneBit(long i) {
// HD, Section 2-1
return i & -i;
}

/**
* 该方法返回i的二进制从头开始有多少个0
* i为0的话则有64个0
* 这里处理其实是体现了二分查找思想的,先看高32位是否为0,是的话则至少有32个0,否则左移16位继续往下判断,接着右移24位看是不是为0,是的话则至少有16+8=24个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;
}

// 与前面的numberOfLeadingZeros方法对应,该方法返回i的二进制从尾开始有多少个0.它的思想和前面的类似,也是基于二分查找思想
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);
}

/**
* 该方法主要用于计算二进制数中1的个数,都是移位和加减操作
* 0x5555555555555555L等于0101010101010101010101010101010101010101010101010101010101010101
* 0x3333333333333333L等于0011001100110011001100110011001100110011001100110011001100110011
* 0x0f0f0f0f0f0f0f0fL等于0000111100001111000011110000111100001111000011110000111100001111
* 它的核心思想就是先每两位一组统计看有多少个1
* 比如10011111则每两位有1、1、2、2个1,记为01011010,然后再算每四位一组看有多少个1,而01011010则每四位有2、4个1,记为00100100,接着每8位一组就为00000110,接着16位,32位,64位,最终在与0x7f进行与运算,得到的数即为1的个数
*/
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;
}

/**
* 返回通过将指定的值的二进制补码表示形式向左旋转指定位数而获得的值
*/
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);
}

/**
* 该方法即是将i进行反转,反转就是第1位与第64位对调,第二位与第63位对调,以此类推
* 它的核心思想是先将相邻两位进行对换,比如10100111对换01011011,接着再将相邻四位进行对换,对换后为10101101,接着将相邻八位进行对换,最后把64位中中间的32位对换,然后最高16位再和最低16位对换
*/
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;
}

/**
* 指定long值的符号函数
* 如果指定值为负,则返回值-1;如果指定值为零,则返回 0;如果指定值为正,则返回1)
*/
public static int signum(long i) {
// HD, Section 2-7
return (int) ((i >> 63) | (-i >>> 63));
}

/**
* 返回通过反转指定 long 值中字节的顺序而获得的值
*/
public static long reverseBytes(long i) {
i = (i & 0x00ff00ff00ff00ffL) << 8 | (i >>> 8) & 0x00ff00ff00ff00ffL;
return (i << 48) | ((i & 0xffff0000L) << 16) |
((i >>> 16) & 0xffff0000L) | (i >>> 48);
}
文章作者: Eric Liang
文章链接: https://ericql.github.io/2019/11/12/01-Java%E5%9F%BA%E7%A1%80%E7%AF%87/02-JDK%E6%BA%90%E7%A0%81%E7%AF%87/Long%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Eric Liang
打赏
  • 微信
  • 支付宝