實現了 Comparable
接口,用於兩個 Long
型變量直接的比較。全部的包裝類型都實現了該接口。java
/** * Long 型最小值,-2^63 * have, -2<sup>63</sup>. */
@Native public static final long MIN_VALUE = 0x8000000000000000L;
/** * Long 型最大值,2^63 - 1 */
@Native public static final long MAX_VALUE = 0x7fffffffffffffffL;
/** * 基礎類型 long 的 Class 對象 */
@SuppressWarnings("unchecked")
public static final Class<Long> TYPE = (Class<Long>) Class.getPrimitiveClass("long");
/** * 實際存儲 Long 變量的值 */
private final long value;
/** * long 型值的位數 */
@Native public static final int SIZE = 64;
複製代碼
private static class LongCache {
private LongCache(){}
// 緩存,範圍從 -128 到 127,+1 是由於有個 0
static final Long cache[] = new Long[-(-128) + 127 + 1];
// 靜態代碼塊,容器初始化時,進行加載
static {
// 緩存 Long 值,注意這裏是 i - 128 ,因此獲取的時候就須要 + 128
for(int i = 0; i < cache.length; i++)
cache[i] = new Long(i - 128);
}
}
複製代碼
Long
在內部類中實現了緩存機制,緩存了 [-128,127]
的全部 Long
值,若是是該範圍內的 Long
值,將直接從緩存中獲取。git
/** * 構建一個新對象,對象值爲 value */
public Long(long value) {
this.value = value;
}
/** * 使用 parseLong 方法將傳入的 s 轉化成 Long 值 */
public Long(String s) throws NumberFormatException {
this.value = parseLong(s, 10);
}
複製代碼
public static Long valueOf(long l)
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
方法會根據傳入的 long
值的範圍來判斷是否從緩存中獲取值。在 LongCache
類中 cache
數組初始化時,索引 index
對應的值爲 index - 128
,所以這裏使用 cache
數組時增長了向右偏移了 128
位。數組
public static long parseLong(String s)
public static long parseLong(String s) throws NumberFormatException {
// 默認 s 中的 long 值爲十進制
return parseLong(s, 10);
}
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");
}
long result = 0;
boolean negative = false;//是否爲負數標識
int i = 0, len = s.length();
long limit = -Long.MAX_VALUE;
long multmin;
int digit;//存儲每位字符的數值
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar < '0') {
// 若是字符串第一位 ASC 碼 < '0',那第一位必須爲 '+' 或 '-',且字符串位數必須大於 1
if (firstChar == '-') {
negative = true;
limit = Long.MIN_VALUE;
} else if (firstChar != '+')
throw NumberFormatException.forInputString(s);
if (len == 1)
throw NumberFormatException.forInputString(s);
i++;
}
// 執行 result *= radix 前 result 的最小值
multmin = limit / radix;
while (i < len) {
// 累減,避免計算溢出問題影響結果
// 計算出 s.charAt(i++) 在 radix 進制下的值
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;
}
複製代碼
parseLong
方法使用累減來計算 result
。由於當數值接近 MAX_VALUE
時,累加產生的溢出值,會影響判斷的結果,而累減產生的溢出值不會。緩存
這裏和 valueOf(String)
對比能夠看出,valueOf(String)
方法會去使用 Long
的緩存機制,而 parseLong
不會。因此在實際使用中,首選使用 valueOf(String)
。less
包裝類在使用中很簡單,基本上都是調用類型轉化的方法。this
在包裝類型中 ,Float
和 Double
沒有實現緩存機制。spa
在 parseLong(String)
的方法實現中,設計者使用了累減而不是累加來統計參數已轉化出來的 result
,這樣能夠避免在後面與 limit
比較時,產生溢出對判斷結果形成影響。在 jdk
源碼中,有不少這樣的奇淫巧技,多瞭解細節能夠進一步提高本身。設計