整理一些 JDK 中 Integer 實用但不常用的方法

DoubleFJ發表於2018-09-26

個人部落格:DoubleFJ の Blog

直接開搞。

toString

該方法進行了過載,一種是 toString(int i, int radix),另一個是 toString(int i)。一個引數的方法就相當於 toString(int i, 10),看程式碼便知,何況其官網註釋也有:

    public static String toString(int i, int radix) {
        if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
            radix = 10;

        /* Use the faster version */
        if (radix == 10) {
            return toString(i);
        }
        // int 32位
        char buf[] = new char[33];
        boolean negative = (i < 0);
        int charPos = 32;

        if (!negative) {
            i = -i;
        }
        // 根據進製取餘轉換
        while (i <= -radix) {
            buf[charPos--] = digits[-(i % radix)];
            i = i / radix;
        }
        buf[charPos] = digits[-i];

        if (negative) {
            buf[--charPos] = '-';
        }

        return new String(buf, charPos, (33 - charPos));
    }

不過該方法需注意: If the first argument is negative, the first element of the result is the ASCII minus character '-' ('\u005Cu002D'). If the first argument is not negative, no sign character appears in the result.例如:

Integer.toString(-44, 2)  // -101100
Integer.toBinaryString(-44) // 11111111111111111111111111010100

若是負數,用該方法求得的值只是正數前加了個 “-” 。

toBinaryString

類似的幾個方法也一併列出了。 toBinaryString(int i) 轉二進位制方法,toOctalString(int i) 轉八進位制方法,toHexString(int i) 轉十六進位制方法。

Integer.toBinaryString(-44) // 11111111111111111111111111010100
Integer.toOctalString(44) // 54
Integer.toHexString(44) // 2c

parseUnsignedInt

與 toString 方法一樣進行了過載。 parseUnsignedInt(String s)parseUnsignedInt(String s, int radix) 這是 JDK 1.8 新增的方法,作用就是將字串引數解析為第二個引數指定的基數中的無符號整數。

Integer.parseUnsignedInt("11111111111111111111111111010100", 2) // -44
Integer.parseUnsignedInt("44", 10) // 44
Integer.parseUnsignedInt("44") // 44

decode

該方法將 String 解碼為整數。 接受指定語法的十進位制,十六進位制和八進位制數。原始碼如下:

    public static Integer decode(String nm) throws NumberFormatException {
        int radix = 10;
        int index = 0;
        boolean negative = false;
        Integer result;

        if (nm.length() == 0)
            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) { // 0 後面長度要大於 1
            index ++;
            radix = 8;
        }

        if (nm.startsWith("-", index) || nm.startsWith("+", index))
            throw new NumberFormatException("Sign character in wrong position");

        try {
            result = Integer.valueOf(nm.substring(index), radix);
            result = negative ? Integer.valueOf(-result.intValue()) : result;
        } catch (NumberFormatException e) {
            // If number is Integer.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 = Integer.valueOf(constant, radix);
        }
        return result;
    }

使用測試如下:

Integer.decode("0xff") // 255
Integer.decode("#ff") // 255
Integer.decode("-07") // -7
Integer.decode("-071") // -57

highestOneBit

該方法返回一個 int 值,該值最多隻有一位,位於指定 int 值中最高位(“最左側”)1 的位置。 如果指定的值在其二進位制補碼錶示中沒有一位,即,如果它等於零,則返回零。

Integer.highestOneBit(44) // 32

44 對應的二進位制為 0010 1100,只選中其最左側的 “1” 那就是 0010 0000,也就是 25 = 32

lowestOneBit

該方法返回一個 int 值,該值最多隻有一位,位於指定 int 值中最低位(“最右側”)1 的位置。 如果指定的值在其二進位制補碼錶示中沒有一位,即,如果它等於零,則返回零。

Integer.lowestOneBit(44) // 4

44 對應的二進位制為 0010 1100,只選中其最右側的 “1” 那就是 0000 0100,也就是 22 = 4

numberOfLeadingZeros

該方法計算首部零的個數。

    /**
     * 首先在 jvm 中一個 int 型別的資料佔 4 個位元組,共 32 位,其實就相當於一個長度為 32 的陣列。
     *
     * 那我們要計算首部 0 的個數,就是從左邊第一個位開始累加 0 的個數,直到遇到一個非零值。
     */
    public static int numberOfLeadingZeros(int i) {
        // HD, Figure 5-6
        if (i == 0)
            return 32;
        int n = 1;
        // 下面的程式碼就是定位從左邊開始第一個非零值的位置,在定位過程中順便累加從左邊開始 0 的個數
        // 將 i 無符號右移 16 位後,有二種情況;
        //   情況1. i=0,則第一個非零值位於低 16 位,i 至少有 16 個 0,同時將 i 左移 16 位(把低 16 位移到原高 16 位的位置,這樣情況 1 和情況 2 就能統一後續的判斷方式)
        //   情況2. i!=0,則第一個非零值位於高 16 位,後續在高 16 位中繼續判斷
        // 這個思路就是二分查詢,首先把32位的數分為高低 16 位,如果非零值位於高 16 位,後續再將高 16 位繼續二分為高低 8 位,一直二分到集合中只有 1 個元素
        if (i >>> 16 == 0) { n += 16; i <<= 16; }
        // 判斷第一個非零值是否位於高 8 位
        if (i >>> 24 == 0) { n +=  8; i <<=  8; }
        // 判斷第一個非零值是否位於高 4 位
        if (i >>> 28 == 0) { n +=  4; i <<=  4; }
        // 判斷第一個非零值是否位於高 2 位
        if (i >>> 30 == 0) { n +=  2; i <<=  2; }
        n -= i >>> 31;
        return n;
    }

測試看看:

Integer.numberOfLeadingZeros(44) // 26

int 4 個位元組,一個位元組八位,所以有 32 位。44 對應完整二進位制就是 0000 0000 0000 0000 0000 0000 0010 1100。所以從左邊開始數起共有 26 個零。

numberOfTrailingZeros

返回指定 int 值的二進位制補碼錶達式中最低位(“最右側”)1 之後的零位數。

Integer.numberOfTrailingZeros(44) // 2

44 對應二進位制 0010 1100。其最右側 “1” 之後的零的個數就是 2。

bitCount

返回指定 int 值的二進位制補碼中 1 的個數。

Integer.bitCount(44) // 3
Integer.bitCount(-44) // 28

44 對應的二進位制補碼為 0000 0000 0000 0000 0000 0000 0010 1100。1 有 3 個。

-44 對應的二進位制補碼為 1111 1111 1111 1111 1111 1111 1101 0100。1 有 28 個。


End.

相關文章