程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java Integer剖析

Java Integer剖析

編輯:關於JAVA

Java Integer剖析。本站提示廣大學習愛好者:(Java Integer剖析)文章只能為提供參考,不一定能成為您想要的結果。以下是Java Integer剖析正文


Java Integer剖析 獲取String的整型值的方法
  • public Integer valueOf(String str) Java獲取字符串的十進制Integer整型值
public static Integer valueOf(String s) throws NumberFormatException {
    return Integer.valueOf(parseInt(s, 10));
}

底層調用的是Integer.parseInt(String s, int radix),然後通過Integer.valueOf(int i)將parseInt返回的int值封裝成Integer對象。

注意:Integer.valueOf(int i)中對需要封裝成Integer的int值做了緩存,常用的Integer值,默認[-128~127]可直接通過緩存獲取,否則新建Integer。這樣也就導致了一個Integer的自動裝箱的問題,後面談到equals==時我們再來分析。

public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];//IntegerCache數組中存在,直接返回Integer 對象,否則創建新Integer對象
    return new Integer(i);
}

當然這裡的緩存int的最大值是可以設置的,通過java.lang.Integer.IntegerCache.high屬性來設置。

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            int i = parseInt(integerCacheHighPropValue);
            i = Math.max(i, 127);//默認最小的max值是127
            // Maximum array size is Integer.MAX_VALUE
            h = Math.min(i, Integer.MAX_VALUE - (-low) -1);//確保cache數組的大小不超過Integer的最大限度
        }
        high = h;

        cache = new Integer[(high - low) + 1];//創建緩存數組,給定大小
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);//初始化緩存數組
    }

    private IntegerCache() {}
}
  • public int parseInt(String str) 解析String的int值,返回int型數值

parseInt(String str) ,底層調用int parseInt(String s, int radix), radix默認10

public static int parseInt(String s) throws NumberFormatException { return parseInt(s,10); }

parseInt(String s, int radix)的實現如下。這個方法也是很著名的atoi(字符串轉int),面試題裡面出現的概率很高——想想如果讓自己寫代碼來實現,能否寫的出來?

/**
*@param s 要轉換成int的String字符串。parseInt只接收帶‘+’,‘-’或純數值(8進制,16進制,10進制),不自動判斷進制數, 需要靠後面的radix來指定———區別於decode(String str)
*@param radix String字符串中的數字的進制數
*@return 轉換後的十進制數
*/
public static int parseInt(String s, int radix)
            throws NumberFormatException
{
    /*
     * WARNING: This method may be invoked early during VM initialization
     * before IntegerCache is initialized. Care must be taken to not use
     * the valueOf method.
     */

    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");
    }

    int result = 0;
    boolean negative = false;
    int i = 0, len = s.length();
    int limit = -Integer.MAX_VALUE;
    int multmin;
    int digit;

    if (len > 0) {
        char firstChar = s.charAt(0);
        if (firstChar < '0') { // Possible leading "+" or "-"
            if (firstChar == '-') {
                negative = true;
                limit = Integer.MIN_VALUE;
            } else if (firstChar != '+')
                throw NumberFormatException.forInputString(s);

            if (len == 1) // Cannot have lone "+" or "-"
                throw NumberFormatException.forInputString(s);
            i++;
        }
        multmin = limit / radix;
        while (i < len) {
            // Accumulating negatively avoids surprises near MAX_VALUE
            digit = Character.digit(s.charAt(i++),radix);//獲取char的int值
            if (digit < 0) {
                throw NumberFormatException.forInputString(s);
            }
            if (result < multmin) {
                throw NumberFormatException.forInputString(s);
            }
            result *= radix;//如傳入String為“123”,radix為10.計算過程為i = ((-1*10 - 2)*10 - 3)*10 
            if (result < limit + digit) {
                throw NumberFormatException.forInputString(s);
            }
            result -= digit;
        }
    } else {
        throw NumberFormatException.forInputString(s);
    }
    return negative ? result : -result;
}

parseInt(String s,int radix)就是求int radix進制數String sradix進制數是多少。

  • Integer decode(String nm) decode方法可以接收帶有'0x', '0X', '#'(16進制),'0'(8進制)前綴的字符串,自動判斷進制數,底層調用的Integer.valueOf(String str, int radix)——>Integer.parseInt(String str, int radix)

decode(String str)相對於parseInt(String str, int radix)多了自動判斷進制數的功能,且返回值是Integer對象。

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) {
        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);//底層調用valueOf(String str, int radix) --> parseInt(String str, int 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.getInteger(String str, Integer val); 此方法用於獲取系統屬性的Integer值
/**
* 如果需要獲取系統的屬性值的話,推薦使用getInteger(String nm, Integer val),可以省去一層調用和一個判斷
*/
public static Integer getInteger(String nm, int val) {
    Integer result = getInteger(nm, null);
    return (result == null) ? Integer.valueOf(val) : result;
}
/**
*@param nm 系統屬性的名字,如"java.lang.Integer.IntegerCache.high"
*@param val 獲取系統屬性失敗的情況下的默認值
*@return 屬性對應的Integer值
*/
public static Integer getInteger(String nm, Integer val) {
    String v = null;
    try {
        v = System.getProperty(nm);
    } catch (IllegalArgumentException e) {
    } catch (NullPointerException e) {
    }
    if (v != null) {
        try {
            return Integer.decode(v);//底層調用的decode,把str解析成對應的十進制Integer
        } catch (NumberFormatException e) {
        }
    }
    return val;
}
總結 Atoi使用推薦 返回值Integer 返回值int str是十進制 valueOf(String str) parseInt(String str) str非十進制 decode(String str)(需解析radix) |valueOf(String str, int radix)(不需要解析radix) parseInt(String str, int radix)(str不能帶radix標識,但可以帶‘+’、‘-’號) Integer中的其它方法
  • compareTo(Integer anotherInteger) 比較兩個Integer數值的大小
/**
* @param 要比較的另一個Integer
* @return 相等返回0,小於anotherInteger返回-1,大於anotherInteger返回1
*/
public int compareTo(Integer anotherInteger) {
    return compare(this.value, anotherInteger.value);
}

底層使用的方法

public static int compare(int x, int y) {
    return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
  • Integer中的equals方法
public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

關於equals(Object obj)==,自動裝箱的坑

前兩天看到一個面試題,大體就是下面這樣的代碼:

public class Test {
    public static void main(String[] args) throws Exception {
        Integer i1 = 10, i2 = 10, i3 = 128, i4 = 128;
        System.out.println(i1 == i2);
        System.out.println(i1.equals(i2));
        System.out.println(i3 == i4);
        System.out.println(i3.equals(i4));
    }
}

看這一段代碼,我第一反應就是

true
true
true
true

結果實際執行效果是

true
true
false
true

仔細研究了一下,發現JVM在自動拆裝箱的時候會調用valueOf()方法,讓我們來看一下Integer的valueOf()方法:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

注釋裡寫明了Integer會緩存[-128, 127]之間的值,結合代碼也可以看出如果Integer對象攜帶的整形如果是[128, 127]之間則直接返回這個Integer,否則新建一個Integer。

這個坑就顯而易見了, Java中==比較的是地址,兩個不同的對象地址顯然不一樣,所以會有上面令我匪夷所思的結果。 
這坑讓我意識到即使Java裡有自動拆裝箱, 也不能依賴這個特性,否則就是深淵吶,對象還是老老實實的用equals(T)比較吧

  • toString()方法
public static String toString(int i) {
    if (i == Integer.MIN_VALUE)
        return "-2147483648";
    int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
    char[] buf = new char[size];
    getChars(i, size, buf);
    return new String(buf, true);
}

相關的方法實現

  • [ ] stringSize(int x); 返回正整數x的位數
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                                  99999999, 999999999, Integer.MAX_VALUE };

// Requires positive x, 返回正整數x的位數
static int stringSize(int x) {
    for (int i=0; ; i++)
        if (x <= sizeTable[i])
            return i+1;
}
static void getChars(int i, int index, char[] buf) {
    int q, r;
    int charPos = index;
    char sign = 0;

    if (i < 0) {
        sign = '-';
        i = -i;
    }

    // Generate two digits per iteration
    while (i >= 65536) {
        q = i / 100;
    // really: r = i - (q * 100);
        r = i - ((q << 6) + (q << 5) + (q << 2));
        i = q;
        buf [--charPos] = DigitOnes[r];
        buf [--charPos] = DigitTens[r];
    }

    // Fall thru to fast mode for smaller numbers
    // assert(i <= 65536, i);
    for (;;) {
        q = (i * 52429) >>> (16+3);
        r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...
        buf [--charPos] = digits [r];
        i = q;
        if (i == 0) break;
    }
    if (sign != 0) {
        buf [--charPos] = sign;
    }
}
  • int signum(int i); 判斷i的值是否大於0,如果i是正數,返回1;i等於0,返回0;i為負數,返回-1.
public static int signum(int i) {
  // HD, Section 2-7
  return (i >> 31) | (-i >>> 31);
}
Integer高級方法總結
  • //highestOneBit。保留最高位的1,同時將低位全部清零

java System.out.println(Integer.highestOneBit(1023)); System.out.println("lowest one bit: " + Integer.lowestOneBit(12));

  • //numberOfLeadingZeros。返回最高位的1之前0的個數。例如:1101000即104返回32-7=25
System.out.println("number of leading zeros: " + Integer.numberOfLeadingZeros(104));//25
System.out.println("number of leading zeros: " + Integer.numberOfLeadingZeros(2));//30
  • //numberOfTrailingZeros。返回最低位的1之後0的個數。例如:1101000即104返回3

System.out.println("number of trailing zeros: " + Integer.numberOfTrailingZeros(104));//3

  • //reverse。反轉二進制補碼中位的順序。即將第32位的值與第1位的值互換,第31位的值與第2位的值互換,等等,依次
System.out.println("reverse: " + Integer.toBinaryString(Integer.reverse(7)));//得11100000000,即最低位的三個一跑到最高位去了
System.out.println("reverse: " + Integer.toBinaryString(Integer.reverse(13)));//得到101100000
  • //reverseBytes:將第一個字節與第四個字節的位置互換,第二個字節與第三個字節位置互換

System.out.println("reverse bytes: " + Integer.toHexString(Integer.reverseBytes(0x4835)));//打印35480000

  • //rotateLeft。將i左移distance,如果distance為負,則右移-distance
System.out.println("rotate left: " + Integer.rotateLeft(7, 2));//打印28

System.out.println("rotate left: " + Integer.rotateLeft(28, -2));//實際為向右移2,打印7
  • //rotateRight。將i無符號右移distance,如果distance為負,則左移-distance。負的肯定會移成正的。

System.out.println("rotate left: " + Integer.rotateRight(-7, 2));//打印28

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved