我是靠谱客的博主 可耐高跟鞋,这篇文章主要介绍java源码分析---Long类(JDK14),现在分享给大家,希望可以做个参考。


更多源码分析,请点击


Long

Long 类将基本类型 long 的值包装在对象中。 Long 类型的对象包含一个类型为 long 的属性。

另外,提供了几种将 long 转换为 StringString 转换为 long 的方法,以及其他在处理 long 类型时有用的方法。

Long 类被 final 关键字修饰,不能被继承。Long 类继承自 Number 类,实现了 ComparableConstableConstantDesc 接口。

复制代码
1
2
3
4
5
6
7
8
9
10
public final class Long extends Number implements Comparable<Long>, Constable, ConstantDesc { private final long value; @Native public static final long MIN_VALUE = 0x8000000000000000L; @Native public static final long MAX_VALUE = 0x7fffffffffffffffL; @Native public static final int SIZE = 64; public static final int BYTES = SIZE / Byte.SIZE; public static final Class<Long> TYPE = (Class<Long>) Class.getPrimitiveClass("long"); }

value 为常量,用于保存 Long 对象所对应的基本类型 long 的值。

SIZE 为静态常量,用于表示二进制补码形式的 long 类型所需要的位数。

BYTES 为静态常量,用于表示二进制补码形式的 long 值所占的字节数。即8个字节。

TYPE 为静态常量,基本类型 longClass 对象。

MIN_VALUE 为静态常量, long 型所能表示的最小数 263-1

MAX_VALUE 为静态常量, long 型所能表示的最小数 -263

@Native 指示可以从本地代码引用定义常量值的字段。

Long 类的构造方法很少使用,并且官方不推荐使用,推荐使用 valueOf(long) 方法。

LongCache

静态内部类,并且是私有的。定义了一个静态常量数组 cache 用来存储 Long 类 [-128, 127] 区间中的值。

在类中使用静态代码块初始化 cache 的值,size 的大小即为[-128, 127] 区间中的值的数量,共256个。然后依次创建这些对象,并将其保存在 cache 中。避免了重复的创建对象,方便调用和回收。

注意:静态代码块只在类加载的时候执行一次。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private static class LongCache { private LongCache() {} static final Long[] cache; static Long[] archivedCache; static { int size = -(-128) + 127 + 1; // Load and use the archived cache if it exists VM.initializeFromArchive(LongCache.class); if (archivedCache == null || archivedCache.length != size) { Long[] c = new Long[size]; long value = -128; for(int i = 0; i < size; i++) { c[i] = new Long(value++); } archivedCache = c; } cache = archivedCache; } }

toString(long)

返回表示指定整数的 String 对象。该参数将转换为带符号的十进制表示形式,并作为字符串返回。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
public static String toString(long i) { int size = stringSize(i); if (COMPACT_STRINGS) { byte[] buf = new byte[size]; getChars(i, size, buf); return new String(buf, LATIN1); } else { byte[] buf = new byte[size * 2]; StringUTF16.getChars(i, size, buf); return new String(buf, UTF16); } }
  • 调用 stringSize(long) 方法计算字符串长度。
  • 根据 COMPACT_STRINGS 的值,对字符串采用不同的编码。
  • 创建大小为 sizebyte[] ,调用 getchars(int, int, byte[]) 方法(见下文)将数字以十进制将每一位保存在 byte[] 中。
  • 调用 String 的构造方法,并使用 byte[] 对字符串初始化。
复制代码
1
2
3
4
5
static final boolean COMPACT_STRINGS; static { COMPACT_STRINGS = true; }

COMPACT_STRINGS 定义在 String 类中,并在静态代码块中初始化为 true 。表示该字符串是否可以被压缩,用于具有多个可能实现路径的方法。(java 9 新特性)

这个字段的实际值是由JVM注入的。静态初始化块用于设置这里的值,以表明这个静态final字段不可静态折叠,并避免在vm初始化期间任何可能的循环依赖。

实例字段值通常对于优化JIT编译器是不透明的。因此,在性能敏感的地方,首先检查静态布尔 COMPACT_STRINGS,然后再检查编码器字段

Latin1是ISO-8859-1的别名,有些环境下写作Latin-1。ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。
ISO-8859-1收录的字符除ASCII收录的字符外,还包括西欧语言、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。ASCII编码是一个7位的容器,ISO-8859-1编码是一个8位的容器。

stringSize(long)

返回给定 long 值的字符串表示所需要的长度。

  • 如果 x 为负数,d 等于1;否则,d 等于0。因为如果 x 为负数,字符串的第一个字符应该为 ‘-’。

  • 如果 x 是正数,将 x 装换成负数进行计算,方法如下:

  • 判断 x 是否大于 -10 ,如果大于,说明 x 在区间 [-9, 0] 之间。即 x 只有1位。

  • 如果 x 小于 -10,则给 -10×10,比较 x 与 -100 的大小,依次类推……

  • 求出数字所需要的位数,加上符号位 d 的长度,即为字符串所需要的长度。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static int stringSize(long x) { int d = 1; if (x >= 0) { d = 0; x = -x; } long p = -10; for (int i = 1; i < 19; i++) { if (x > p) return i + d; p = 10 * p; } return 19 + d; }

getChars(long, int, byte[])

将代表整数 i 的字符放入字符数组 buf 。字符从指定索引处的最低有效数字(不包括最高字符)开始向前放置

复制代码
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
static int getChars(long i, int index, byte[] buf) { long q; int r; int charPos = index; boolean negative = (i < 0); if (!negative) { i = -i; } // Get 2 digits/iteration using longs until quotient fits into an int while (i <= Integer.MIN_VALUE) { q = i / 100; r = (int)((q * 100) - i); 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 <= -100) { q2 = i2 / 100; r = (q2 * 100) - i2; i2 = q2; buf[--charPos] = Integer.DigitOnes[r]; buf[--charPos] = Integer.DigitTens[r]; } // We know there are at most two digits left at this point. q2 = i2 / 10; r = (q2 * 10) - i2; buf[--charPos] = (byte)('0' + r); // Whatever left is the remaining digit. if (q2 < 0) { buf[--charPos] = (byte)('0' - q2); } if (negative) { buf[--charPos] = (byte)'-'; } return charPos; }
  • 如果整数 i 是正数,将其转换为负数。
  • i 小于100时,每次对 i 除以 100,然后再乘以100,减去 i ,可以得到 i 除 100 的余数 r,通过数组 DigitOnesDigitTens 分别取到 r 的个位和十位存到数组 buf 中,依此循环。
  • 当 i 大于100 时,不能直接通过数组 DigitOnesDigitTens 获得数字,因为不能确定此时 i 的位数。所以对 i 除 10 求余数将其存放再数组 buf 中,如果 q 仍小于 0,说明最高位就是 q ,将其保存再数组 buf 中。
  • 根据符号标志 negative 判断数字是否为负数,如果是负数,则在 buf 数组最前面加上负号。

思考:为什么将正数转化为负数?

因为 long 型整数的范围为 [-263 , 263-1],将正数转换为负数,以覆盖 Long.MIN_VALUE 的情况。否则(将负数转换为正数),转换将暴露 -Long.MIN_VALUE,该整数将溢出。

思考:为什么 (‘0’ + r)但是(’0’ - q2)?

因为 r 的结果是正数,而 q 的计算结果是负数( i 为负数)。

toString(long, int)

将给定的数字 i 以 radix 进制的字符串形式返回。

复制代码
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
public static String toString(long i, int radix) { if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) radix = 10; if (radix == 10) return toString(i); if (COMPACT_STRINGS) { byte[] buf = new byte[65]; int charPos = 64; boolean negative = (i < 0); if (!negative) { i = -i; } while (i <= -radix) { buf[charPos--] = (byte)Integer.digits[(int)(-(i % radix))]; i = i / radix; } buf[charPos] = (byte)Integer.digits[(int)(-i)]; if (negative) { buf[--charPos] = '-'; } return StringLatin1.newString(buf, charPos, (65 - charPos)); } return toStringUTF16(i, radix); } public static String newString(byte[] val, int index, int len) { return new String(Arrays.copyOfRange(val, index, index + len), LATIN1); }
  • 如果进制 radix 小于 Character.MIN_RADIX (2) 或者大于 Character.MAX_RADIX (36) 。采用 10 进制。
  • 如果 radix == 10 ,直接调用 toString(long) 方法。
  • 否则,先根据 COMPACT_STRINGS 的值,对字符串采用不同的编码。
  • 如果为 true ,即采用 LATIN1 编码:1)先初始化一个大小为 65 的数组,从最后一位,即索引 64 处开始存放数据。2)如果 i 为正数,将 i 转换为负数。当 i 小于等于 -radix ,循环取余,将余数通过数组 digits 转化为 radix 进制数保存到 buf 数组中。3)如果是负数,在加上负号。4)调用 StringLatin1.newString() 方法以 buf 数组中从索引 charPos 处开始初始化 String 对象返回。(本质上就是通过数组拷贝的方式将 buf 数组中有效的部分(即从索引 charPos 开始之后的数据)复制一份作为 String 对象的初始值,并设置编码方式为 LATIN1 )。
  • 否则,采用 UTF16 编码,调用 toStringUTF16() 方法实现。

思考:为什么进制数不能超过 36

因为 26 个英文字母,加上0到9一共 10 个数字,一共36个字符,最多表示 36 进制的数。

思考:为什么初始化数组 buf 的大小为 65

因为 long 型数据最大长度为 64 位(如果以2进制形式表示),如果是负数的话,需要加上负号,一共65位。

toStringUTF16(long, int)

将给定的数字 iradix 进制的字符串形式返回。字符串编码方式为 UTF16 。具体实现原理和上述 toString(long, int) 方法相似,这里不再赘述。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private static String toStringUTF16(long i, int radix) { byte[] buf = new byte[65 * 2]; int charPos = 64; boolean negative = (i < 0); if (!negative) { i = -i; } while (i <= -radix) { StringUTF16.putChar(buf, charPos--, Integer.digits[(int)(-(i % radix))]); i = i / radix; } StringUTF16.putChar(buf, charPos, Integer.digits[(int)(-i)]); if (negative) { StringUTF16.putChar(buf, --charPos, '-'); } return StringUTF16.newString(buf, charPos, (65 - charPos)); }

putChar()

复制代码
1
2
3
4
5
6
7
8
9
@HotSpotIntrinsicCandidate static void putChar(byte[] val, int index, int c) { assert index >= 0 && index < length(val) : "Trusted caller missed bounds check"; index <<= 1; val[index++] = (byte)(c >> HI_BYTE_SHIFT); val[index] = (byte)(c >> LO_BYTE_SHIFT); }

assert,断言,如果后面表达式为真,不采取任何措施,否则,抛出 AssertionError() ,后面的字符串即传入该错误的构造函数的值。

因为是采用 UTF16 编码形式,所以需要对索引index左移一位。然后将字符 c 的值拷贝到 buf 数组中。

newString()

newString() 方法底层调用 Arrays.copyOfRange() 方法实现区间 [start, end) 范围内的字符串复制。

复制代码
1
2
3
4
public static String newString(byte[] val, int index, int len) { return new String(Arrays.copyOfRange(val, index, index + len), LATIN1); }

toUnsignedString(long, int)

返回指定数字 iradix 进制的无符号整数(不将符号位当作符号处理)的字符串表示形式。

  • 如果 i 大于等于零,直接调用 toString(long, int) 方法(见上文)实现。
  • 如果 i 小于零,根据进制数 radix 的不同,调用不同的方法实现。具体方法实现请看下文关于各方法的详解。
复制代码
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
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); } } }

toUnsignedBigInteger(long)

将整数 i 转换成一个 BigInteger 对象返回。

将字符分成两部分低32位和高32位分别计算

  • 使用 Integer.toSignedLong(int) 方法分别将两部分转换为 long 型整数。
  • 使用 BigInteger.valueOf(long) 方法将 long 型整数转换为 BigInteger 对象。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
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))); } }

toBinaryString(long)

返回指定数字 i2 进制的无符号整数的字符串表示形式。调用 toUnsignedString0(long, int) 方法实现。

复制代码
1
2
3
4
public static String toBinaryString(long i) { return toUnsignedString0(i, 1); }

toOctalString(long)

返回指定数字 i8 进制的无符号整数的字符串表示形式。调用 toUnsignedString0(long, int) 方法实现。

复制代码
1
2
3
4
public static String toOctalString(long i) { return toUnsignedString0(i, 3); }

toHexString(long)

返回指定数字 i16 进制的无符号整数的字符串表示形式。调用 toUnsignedString0(long, int) 方法实现。

复制代码
1
2
3
4
public static String toHexString(long i) { return toUnsignedString0(i, 4); }

toUnsignedString0(long, int)

将指定的数字 i 转换成指定进制数的字符串表示形式。

  • 通过 numberOfLeadingZeros() 方法计算出计算出 val 二进制补码表示形式中最高位之前的 0 的个数,从而计算出 val 二进制补码表示中的有效位数。
  • 计算出使用指定进制表示 val 需要的位数。
  • 根据 COMPACT_STRINGS 的值,对字符串采用不同的编码。
  • 如果为 true ,即采用 LATIN1 编码,创建一个长度为 charsbyte 数组,调用 formatUnsignedLong0() 方法(见下文)将 val 转化成指定进制存入 buf 数组中。然后通过 String 的构造方法转换为 String 对象。
  • 否则,采用 UTF16 编码,创建一个长度为 chars × 2byte 数组(因为UTF16编码每个字符占两个字节),调用 formatUnsignedLong0UTF16() 方法(见下文)将 val 转化成指定进制存入 buf 数组中。然后通过 String 的构造方法转换为 String 对象。

思考:为什么上面 toHexString()toOctalString() 方法中调用 toUnsignedString0() 方法的第二个参数分别为 43

因为 4 位二进制数可以表示 1 位16进制数,三位二进制数可以表示1位8进制数。这样在方法中通过 二进制位数/shift 就能计算出用16进制或8进制表示 val 时需要的位数。

思考:为什么要先给二进制位数(mag)加上 shift - 1 之后,再除以 shift ?

假设二进制位数(mag)是 7 位,直接除以 shift(假设此时shift为 4 ),得到的结果为 1 。显然不对,如果先给 7 加上 3 ,结果为 2 。才我们想要的正确结果。读者可以思考那为什么不能使用 mag/shift + 1 的方式计算?看到这里不得不感叹写源码的人真机智????。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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); if (COMPACT_STRINGS) { byte[] buf = new byte[chars]; formatUnsignedLong0(val, shift, buf, 0, chars); return new String(buf, LATIN1); } else { byte[] buf = new byte[chars * 2]; formatUnsignedLong0UTF16(val, shift, buf, 0, chars); return new String(buf, UTF16); } }

numberOfLeadingZeros(long)

返回指定 int 值的二进制补码表示形式中最高位(“最左非零位”)一位之前的零位数目。

复制代码
1
2
3
4
5
6
public static int numberOfLeadingZeros(long i) { int x = (int)(i >>> 32); return x == 0 ? 32 + Integer.numberOfLeadingZeros((int)i) : Integer.numberOfLeadingZeros(x); }

formatUnsignedLong0(long, int, byte[], int, int)

val 转化成指定进制存入 buf 数组中。(LATIN1编码)

  • 从数组最后开始往前存放,通过对 shift 的移位操作计算进制数,1 左移 4 位即16。
  • 通过对 val 和 mask 做 与操作。计算每一位数字,然后将 val 右移 shift 位,循环操作
复制代码
1
2
3
4
5
6
7
8
9
10
private static void formatUnsignedLong0(long val, int shift, byte[] buf, int offset, int len) { int charPos = offset + len; int radix = 1 << shift; int mask = radix - 1; do { buf[--charPos] = (byte)Integer.digits[((int) val) & mask]; val >>>= shift; } while (charPos > offset); }

formatUnsignedLong0UTF16(long, int, byte[], int, int)

val 转化成指定进制存入 buf 数组中。(UTF16编码) 原理同上述方法相同,不再赘述。

复制代码
1
2
3
4
5
6
7
8
9
10
private static void formatUnsignedLong0UTF16(long val, int shift, byte[] buf, int offset, int len) { int charPos = offset + len; int radix = 1 << shift; int mask = radix - 1; do { StringUTF16.putChar(buf, --charPos, Integer.digits[((int) val) & mask]); val >>>= shift; } while (charPos > offset); }

toUnsignedString(long)

返回指定数字 i10 进制的无符号整数(不将符号位当作符号处理)的字符串表示形式。

调用上文中的 toUnsignedString(long, int) 方法实现。点击跳转至该方法

复制代码
1
2
3
4
public static String toUnsignedString(long i) { return toUnsignedString(i, 10); }

parseLong(String, int)

将给定进制 radix 的字符串 s 解析为十进制的有符号整数。

  • 如果字符串 snull,或者进制数 radix 小于2或者大于36,则抛出异常。
  • 判断字符产 s 的第一个字符是否为 ‘-’ 或 ‘+’,
  • 从最高位开始计算,每取一次数字对当前结果乘以 radix 然后加上当前位数字。
  • 判断是否为正数,如果是正数,则需要在结果前加上负号将结果转为正数。
复制代码
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
public static long parseLong(String s, int radix) throws NumberFormatException { if (s == null) { throw new NumberFormatException("null"); } 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"); } boolean negative = false; int i = 0, len = s.length(); long limit = -Long.MAX_VALUE; 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, radix); } if (len == 1) { // Cannot have lone "+" or "-" throw NumberFormatException.forInputString(s, radix); } i++; } long multmin = limit / radix; long result = 0; while (i < len) { // Accumulating negatively avoids surprises near MAX_VALUE int digit = Character.digit(s.charAt(i++),radix); if (digit < 0 || result < multmin) { throw NumberFormatException.forInputString(s, radix); } result *= radix; if (result < limit + digit) { throw NumberFormatException.forInputString(s, radix); } result -= digit; } return negative ? result : -result; } else { throw NumberFormatException.forInputString(s, radix); } }

其他 parseLong(String)parseLong(CharSequence, int, int, int)parseUnsignedLong()系列 方法与上述方法原理一致,这里不再赘述。

valueOf(long)

返回表示指定 long 值的 Long 对象。

如果 l 在区间 [-128, 127] 范围内,直接从缓存中读取,否则,调用构造方法创建对应的 Long 对象。

复制代码
1
2
3
4
5
6
7
8
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(String)

将给定字符串 s (十进制)解析为十进制的有符号整数。

复制代码
1
2
3
4
5
public static Long valueOf(String s) throws NumberFormatException { return Long.valueOf(parseLong(s, 10)); }

valueOf(String, int)

将给定进制 radix 的字符串 s 解析为十进制的有符号整数。

复制代码
1
2
3
4
public static Long valueOf(String s, int radix) throws NumberFormatException { return Long.valueOf(parseLong(s, radix)); }

byteValue()shortValue()intValue()longValue()floatValue()doubleValue() 等方法实现简单,不再赘述。

toString()

String 返回该对象的值。调用 toString(long) 方法实现,前面已经讲过,忘记了点击了解详情。

复制代码
1
2
3
4
public String toString() { return toString(value); }

hashCode(long)

返回 long 型整数的哈希值,将该数字逻辑右移32位,再和原数字求 异或

复制代码
1
2
3
4
public static int hashCode(long value) { return (int)(value ^ (value >>> 32)); }

hashCode()

返回当前对象的哈希值,调用 hashCode() 方法实现。

复制代码
1
2
3
4
public int hashCode() { return Long.hashCode(value); }

equals(Object)

判断当前对象是否与给定的 obj 对象相等。

  • 先判断 obj 是否是 Long 类型,如果是的话,比较他们的值是否相等。
  • 否则,返回 false
复制代码
1
2
3
4
5
6
7
public boolean equals(Object obj) { if (obj instanceof Long) { return value == ((Long)obj).longValue(); } return false; }

getLong(String, Long)

返回指定名称的系统属性 nm 的整数值。val 是默认值。如果没有指定名称的属性,或者该属性的格式不正确,或者指定名称为空或null,则返回默认值。

  • 通过 System.getProperty(String) 方法获取到系统属性。关于该方法,请参考 System 类的源码分析
  • 根据 decode(String) 方法(见下文),将此属性的字符串值解释为整数值,并返回表示该值的 Long 对象。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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; }

decode(String)

将字符串解码为数字,并返回该数字的 Long 对象。

如果属性值以两个ASCII字符 0x 或ASCII字符 开头,而不以减号开头,则将其其余部分解析为十六进制整数,与使用进制数为16的方法 valueOf(String, int) 完全相同。

如果属性值以ASCII字符 0 开头,后跟另一个字符,则该属性值将被解析为八进制整数,与使用进制数为8的 valueOf(String, int) 方法完全相同。

否则,将属性值解析为十进制整数,与使用进制数为10的 valueOf(String, int) 方法完全相同。

关于 valueOf(String, int) 方法可点击跳转至上文查看。

复制代码
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
public static Long decode(String nm) throws NumberFormatException { int radix = 10; int index = 0; boolean negative = false; Long result; if (nm.isEmpty()) 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; }

getLong(String)

返回指定名称的系统属性 nm 的整数值。参考上文中的 getLong(String, Long) 方法。

复制代码
1
2
3
4
public static Long getLong(String nm) { return getLong(nm, null); }

getLong(String, long)

返回指定名称的系统属性 nm 的整数值。val 是默认值。如果没有指定名称的属性,或者该属性的格式不正确,或者指定名称为空或null,则将默认值 val 转为 Long 对象返回。可参考上文中的 getLong(String, Long) 方法。

复制代码
1
2
3
4
5
public static Long getLong(String nm, long val) { Long result = Long.getLong(nm, null); return (result == null) ? Long.valueOf(val) : result; }

compare(long, long)

比较两个 long 型整数的大小

  • 如果 x 小于 y ,返回 -1 。
  • 如果 x 等于 y ,返回 0 。
  • 如果 x 大于 y ,返回 1 。
复制代码
1
2
3
4
public static int compare(long x, long y) { return (x < y) ? -1 : ((x == y) ? 0 : 1); }

compareTo(Long)

比较两个 Long 对象的大小,即比较他们 value 值的大小。

复制代码
1
2
3
4
public int compareTo(Long anotherLong) { return compare(this.value, anotherLong.value); }

compareUnsigned(long, long)

比较两个无符号整数的大小。即最高位不当作符号位进行比较,所以加上 MIN_VALUE 防止超过 long 的表示范围。

复制代码
1
2
3
4
public static int compareUnsigned(long x, long y) { return compare(x + MIN_VALUE, y + MIN_VALUE); }

divideUnsigned(long, long)

将两个数转换为无符号的数,然后相除。

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

remainderUnsigned(long, long)

将两个数转换为无符号的数,然后取余。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
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(); } }

highestOneBit(long)

保留最高位的1,其余位全部置为0。

  • numberOfLeadingZeros(long) 方法返回整数 i 二进制补码形式从左边最高位开始第一个零的位置 index
  • MIN_VALUE 无符号右移 index 位,然后和 i 进行与操作。

例:i = 10,补码形式为 0x000000000000000A,第一个1的位置为60,MIN_VALUE右移28位为 0x0000000000000008

0000……0000 1010 & 0000……0000 1000 —> 0000……0000 1000

复制代码
1
2
3
4
public static long highestOneBit(long i) { return i & (MIN_VALUE >>> numberOfLeadingZeros(i)); }

lowestOneBit(long)

保留最低位的1,其余位全部置0。因为负数的补码是正数每位取反然后加1,所以对正数和负数求与即可。

复制代码
1
2
3
4
5
public static long lowestOneBit(long i) { // HD, Section 2-1 return i & -i; }

numberOfTrailingZeros(long)

返回 long 类型二进制补码表示形式最低为的1的右边有几个零,和 numberOfLeadingZeros(int) 方法原理类似 。

例,10的二进制位 0000……0000 1010,最低位的1的右边只有1个0,返回结果为1。

复制代码
1
2
3
4
5
6
public static int numberOfTrailingZeros(long i) { int x = (int)i; return x == 0 ? 32 + Integer.numberOfTrailingZeros((int)(i >>> 32)) : Integer.numberOfTrailingZeros(x); }

bitCount(long)

返回一个 long 类型的二进制补码表示形式里面有多少个1。

例,10的二进制位 0000……0000 1010,有两个1,那么 bitCount(10) 结果就为2。

  • 核心思想是使用二分法,两两一组相加,之后四个四个一组相加,接着八个八个,最后就得到各位之和了。
  • 第一行是计算每两位中的 1 的个数 , 并且用该对应的两位来存储这个个数 , 如 : 01101100 转换后为 01011000 , 即先把前者每两位分段 01 10 11 00 , 分别有 1 1 2 0 个 1, 用两位二进制数表示为 01 01 10 00, 合起来为 01011000。
  • 第二行是计算每四位中的 1 的个数 , 并且用该对应的四位来存储这个个数 。如 : 01101100 经过第一行计算后得 01011000 , 然后把 01011000 每四位分段成 0101 1000 , 段内移位相加 : 前段 01+01 =10 , 后段 10+00=10, 分别用四位二进制数表示为 0010 0010, 合起来为 00100010 。
  • 下面的各行以此类推 , 分别计算每 8 位 ,16 位 ,32 位, 64位中的 1 的个数。
复制代码
1
2
3
4
5
6
7
8
9
10
11
public static int bitCount(long i) { // HD, Figure 5-2 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; }

rotateLeft(long, int)

返回通过将指定的 long 值的二进制补码循环左移指定的位数获得的值。 (位从左手移出,或移到高阶,在右侧重新移入,或移到低阶。)

(i << distance) 先把尾巴那几位空出来成0,然后(i >>> -distance)获得前面的那几位,然后按位或运算,就旋转了。

注意:向左旋转负距离等于向右旋转:rotateLeft(val, -distance) == rotateRight(val, distance) 。 还要注意,以64的任意倍数进行旋转都是空操作。

复制代码
1
2
3
4
public static long rotateLeft(long i, int distance) { return (i << distance) | (i >>> -distance); }

rotateRight(long, int)

返回通过将指定的 int 值的二进制补码循环右移指定的位数获得的值。和 rotateLeft(long, int) 方法一样。

复制代码
1
2
3
4
public static long rotateRight(long i, int distance) { return (i >>> distance) | (i << -distance); }

reverse(long)

将整数 i 的二进制补码表示形式翻转。即将整数 i 转换为64位二进制数据后,高位和低位对应位置数据互换。

复制代码
1
2
3
4
5
6
7
8
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; return reverseBytes(i); }

reverseBytes(long)

将整数 i 的二进制补码表示形式翻转。即将整数 i 转换为64位二进制数据后,以字节为单位翻转。

复制代码
1
2
3
4
5
6
public static long reverseBytes(long i) { i = (i & 0x00ff00ff00ff00ffL) << 8 | (i >>> 8) & 0x00ff00ff00ff00ffL; return (i << 48) | ((i & 0xffff0000L) << 16) | ((i >>> 16) & 0xffff0000L) | (i >>> 48); }

signum(long)

返回指定 long 值的 signum 函数值。(如果指定的值为负,则返回值为-1;如果指定的值为零,则返回0;如果指定的值为正,则返回1)

复制代码
1
2
3
4
5
public static int signum(long i) { // HD, Section 2-7 return (int) ((i >> 63) | (-i >>> 63)); }

sum(long, long)max(long, long)min(long, loong) 等方法实现简单,不再赘述。

describeConstable()

Constable 接口中的方法。点此了解详情。

复制代码
1
2
3
4
5
@Override public Optional<Long> describeConstable() { return Optional.of(this); }

resolveConstantDesc(MethodHandles.Lookup)

ConstantDesc 接口中的方法,点此了解详情。

复制代码
1
2
3
4
5
@Override public Long resolveConstantDesc(MethodHandles.Lookup lookup) { return this; }

更多源码分析,请点击

最后

以上就是可耐高跟鞋最近收集整理的关于java源码分析---Long类(JDK14)的全部内容,更多相关java源码分析---Long类(JDK14)内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(87)

评论列表共有 0 条评论

立即
投稿
返回
顶部