概述
更多源码分析,请点击
Long
Long 类将基本类型 long 的值包装在对象中。 Long 类型的对象包含一个类型为 long 的属性。
另外,提供了几种将 long 转换为 String 和 String 转换为 long 的方法,以及其他在处理 long 类型时有用的方法。
Long 类被 final 关键字修饰,不能被继承。Long 类继承自 Number 类,实现了 Comparable 、 Constable 、 ConstantDesc 接口。
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 为静态常量,基本类型 long 的 Class 对象。
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 的值,对字符串采用不同的编码。
- 创建大小为 size 的 byte[] ,调用 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,通过数组 DigitOnes 和 DigitTens 分别取到 r 的个位和十位存到数组 buf 中,依此循环。
- 当 i 大于100 时,不能直接通过数组 DigitOnes 和 DigitTens 获得数字,因为不能确定此时 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)
将给定的数字 i 以 radix 进制的字符串形式返回。字符串编码方式为 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)
返回指定数字 i 的 radix 进制的无符号整数(不将符号位当作符号处理)的字符串表示形式。
- 如果 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)
返回指定数字 i 的 2 进制的无符号整数的字符串表示形式。调用 toUnsignedString0(long, int) 方法实现。
public static String toBinaryString(long i) {
return toUnsignedString0(i, 1);
}
toOctalString(long)
返回指定数字 i 的 8 进制的无符号整数的字符串表示形式。调用 toUnsignedString0(long, int) 方法实现。
public static String toOctalString(long i) {
return toUnsignedString0(i, 3);
}
toHexString(long)
返回指定数字 i 的 16 进制的无符号整数的字符串表示形式。调用 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 编码,创建一个长度为 chars 的 byte 数组,调用 formatUnsignedLong0() 方法(见下文)将 val 转化成指定进制存入 buf 数组中。然后通过 String 的构造方法转换为 String 对象。
- 否则,采用 UTF16 编码,创建一个长度为 chars × 2 的 byte 数组(因为UTF16编码每个字符占两个字节),调用 formatUnsignedLong0UTF16() 方法(见下文)将 val 转化成指定进制存入 buf 数组中。然后通过 String 的构造方法转换为 String 对象。
思考:为什么上面 toHexString() 和 toOctalString() 方法中调用 toUnsignedString0() 方法的第二个参数分别为 4 和 3 ?
因为 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)
返回指定数字 i 的 10 进制的无符号整数(不将符号位当作符号处理)的字符串表示形式。
调用上文中的 toUnsignedString(long, int) 方法实现。点击跳转至该方法
public static String toUnsignedString(long i) {
return toUnsignedString(i, 10);
}
parseLong(String, int)
将给定进制 radix 的字符串 s 解析为十进制的有符号整数。
- 如果字符串 s 为 null,或者进制数 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)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复