我是靠谱客的博主 可耐高跟鞋,最近开发中收集的这篇文章主要介绍java源码分析---Long类(JDK14),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述


更多源码分析,请点击


Long

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

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

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

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 中。避免了重复的创建对象,方便调用和回收。

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

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 对象。该参数将转换为带符号的十进制表示形式,并作为字符串返回。

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[] 对字符串初始化。
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 的长度,即为字符串所需要的长度。

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 。字符从指定索引处的最低有效数字(不包括最高字符)开始向前放置

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 进制的字符串形式返回。

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) 方法相似,这里不再赘述。

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()

@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) 范围内的字符串复制。

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 的不同,调用不同的方法实现。具体方法实现请看下文关于各方法的详解。
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 对象。
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) 方法实现。

public static String toBinaryString(long i) {
return toUnsignedString0(i, 1);
}

toOctalString(long)

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

public static String toOctalString(long i) {
return toUnsignedString0(i, 3);
}

toHexString(long)

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

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 的方式计算?看到这里不得不感叹写源码的人真机智????。

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 值的二进制补码表示形式中最高位(“最左非零位”)一位之前的零位数目。

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 位,循环操作
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编码) 原理同上述方法相同,不再赘述。

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) 方法实现。点击跳转至该方法

public static String toUnsignedString(long i) {
return toUnsignedString(i, 10);
}

parseLong(String, int)

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

  • 如果字符串 snull,或者进制数 radix 小于2或者大于36,则抛出异常。
  • 判断字符产 s 的第一个字符是否为 ‘-’ 或 ‘+’,
  • 从最高位开始计算,每取一次数字对当前结果乘以 radix 然后加上当前位数字。
  • 判断是否为正数,如果是正数,则需要在结果前加上负号将结果转为正数。
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 对象。

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 (十进制)解析为十进制的有符号整数。

public static Long valueOf(String s) throws NumberFormatException
{
return Long.valueOf(parseLong(s, 10));
}

valueOf(String, int)

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

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) 方法实现,前面已经讲过,忘记了点击了解详情。

public String toString() {
return toString(value);
}

hashCode(long)

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

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

hashCode()

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

public int hashCode() {
return Long.hashCode(value);
}

equals(Object)

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

  • 先判断 obj 是否是 Long 类型,如果是的话,比较他们的值是否相等。
  • 否则,返回 false
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 对象。
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) 方法可点击跳转至上文查看。

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) 方法。

public static Long getLong(String nm) {
return getLong(nm, null);
}

getLong(String, long)

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

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 。
public static int compare(long x, long y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}

compareTo(Long)

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

public int compareTo(Long anotherLong) {
return compare(this.value, anotherLong.value);
}

compareUnsigned(long, long)

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

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

divideUnsigned(long, long)

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

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)

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

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

public static long highestOneBit(long i) {
return i & (MIN_VALUE >>> numberOfLeadingZeros(i));
}

lowestOneBit(long)

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

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。

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 的个数。
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的任意倍数进行旋转都是空操作。

public static long rotateLeft(long i, int distance) {
return (i << distance) | (i >>> -distance);
}

rotateRight(long, int)

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

public static long rotateRight(long i, int distance) {
return (i >>> distance) | (i << -distance);
}

reverse(long)

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

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位二进制数据后,以字节为单位翻转。

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)

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 接口中的方法。点此了解详情。

@Override
public Optional<Long> describeConstable() {
return Optional.of(this);
}

resolveConstantDesc(MethodHandles.Lookup)

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

@Override
public Long resolveConstantDesc(MethodHandles.Lookup lookup) {
return this;
}

更多源码分析,请点击

最后

以上就是可耐高跟鞋为你收集整理的java源码分析---Long类(JDK14)的全部内容,希望文章能够帮你解决java源码分析---Long类(JDK14)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部