[Java源码]Long

此次来看看Long的源代码,基于 jdk1.8.0_181.jdk 版本,若有错误,欢迎联系指出。html

前言

Longlong基础数据类型的包装类,从源码的角度来看,总体的思路和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;
复制代码

Longlong的包装类,这里存放了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);
  }
}
复制代码

LongCacheLong的静态内部类,内部定义了一个长度为128+127+1=256的数组,用于缓存经常使用的数字范围,避免后续使用时从新进行实例化,提高性能。函数

方法

构造方法

public Long(long value) {
  this.value = value;
}

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

存在两个构造函数,支持传入longString类型参数。但参数类型为String时,内部以十进制格式调用了parseLong方法进行处理实现。post

parseLong 方法

public static long parseLong(String s) throws NumberFormatException public static long parseLong(String s, int radix) throws NumberFormatException 复制代码

存在两个parseLong方法,具体逻辑和IntegerparseInt相似,能够参考相关的文章介绍parseInt 方法

parseUnsignedLong 方法

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

public static long parseUnsignedLong(String s, int radix) throws NumberFormatException 复制代码

存在两个parseUnsignedLong方法,第一个方法内部默认以十进制调用了第二个方法进行实现,方法的总体逻辑与IntegerparseUnsignedInt基本一致,能够参考 parseUnsignedInt 方法

getChars 方法

static void getChars(long i, int index, char[] buf) 复制代码

该方法主要的逻辑就是将输入long类型数据转换成字符形式放入char数组中,不支持 Long.MIN_VALUE。具体逻辑说明能够参考IntegergetChars 方法

stringSize 方法

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位);从逻辑能够看出,只支持正数,负数的结果是错误的。

toString 方法

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

public static String toString(long i) public static String toString(long i, int radix) 复制代码

存在三个toString方法,其中两个为静态方法,与Integer一致,能够参考toString 方法

toUnsignedString 方法

IntegertoUnsignedString方法内部实现调用了LongtoUnsignedString方法进行实现,因此咱们来看看这个方法的实现。

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);
复制代码

根据magshift获取转换成对应进制的字符串所需的字符数(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;
}
复制代码

总体思路就是这样,这样就获取到了对应的字符数组,而后转换成字符串输出结果。

toUnsignedBigInteger 方法

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字节进行处理,而后获取结果。

valueOf 方法

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
复制代码

decode 方法

public static Long decode(String nm) throws NumberFormatException 复制代码

将对应的字符串转换成整数,支持十进制,0x, 0X, #开头的十六进制数,0开头的八进制数。代码逻辑解释能够参考 Integer 的 decode 方法

getLong 方法

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,返回对应的默认值

xxxValue 方法

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;
}
复制代码

直接进行强制类型转换,返回对应的结果

hashCode 方法

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

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

hashCode返回int类型结果,首先将输入参数无符号右移32位,而后与原来的值进行异或运算,强制转换成int类型返回对应的结果。

equals 方法

public boolean equals(Object obj) {
  if (obj instanceof Long) {
    return value == ((Long)obj).longValue();
  }
  return false;
}
复制代码

首先判断是否是Long对象的实例,而后比较二者的值是否相等;这里能够看出咱们无需担忧输入参数为null的时候会出现报错的状况。

compare 方法

public static int compare(long x, long y) {
  return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
复制代码

比较两个参数的值,三元表达式,x < y 时返回-1x == y 时返回0x > y 时返回1

compareTo 方法

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

调用compare方法比较两个值,返回结果与compare方法一致

compareUnsigned 方法

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

两个输入参数看成无符号整数进行比较,这里经过加上MIN_VALUE确保在范围内。有个小技巧,-1加上MIN_VALUE后会变成最大正数。

divideUnsigned 方法

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();
  }
}
复制代码

无符号除法,输入参数转换成无符号数相除获取结果

  • 当除数小于0时,调用compareUnsigned比较除数和被除数,被除数 < 除数时返回0,不然返回1(取决于被除数的正负性)
  • 当除数和被除数均为正数值,直接使用除法运算获取结果
  • 当被除数小于0,除数大于0时,使用toUnsignedBigInteger转换成无符号BigInteger进行运算获取对应的结果

remainderUnsigned 方法

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();
  }
}
复制代码

无符号取余,输入参数转换成无符号数进行取余获取结果。

  • 当除数和被除数均大于0时,直接进行取余运算获取结果
  • 当转换成无符号数,除数小于被除数时,直接返回除数做为结果
  • 不然使用toUnsignedBigInteger方法,二者均转换成无符号BigInteger进行运算获取对应的结果

highestOneBit 方法

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返回结果。

lowestOneBit 方法

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

获取最低位1,其他位为0的值。负数以正数的补码表示,对整数的二进制进行取反码而后加1,获得的结果与输入二进制进行与操做,结果就是最低位1保留,其余位为0。

numberOfLeadingZeros 方法

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 方法中的例子加深了解

numberOfTrailingZeros 方法

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的个数。

bitCount 方法

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 方法介绍,了解其中的运算逻辑

rotateXXX 方法

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)

reverse 方法

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位进行交换就完成了整个过程,全程位运算甚是奇妙。

signum 方法

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

获取符号数,若为负数,返回-1;若为0则返回0;为正数,则返回1。

reverseBytes 方法

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位置

sum、max、min 方法

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 doubleand long,相关解释说明能够参考 double文章中的详细说明。

总结

总的代码逻辑来看,LongInteger的方法基本一致,方法内的实现也基本一致,若是了解了Integer的相关逻辑,Long相关代码能够快速的过一下便可;另外值得注意的是long的原子性问题。

最后

博客地址:blog.renyijiu.com/post/java源码…

相关文章
相关标签/搜索