JAVA類Integer

  • 2019 年 12 月 15 日
  • 筆記

今天帶來的是Integer,想必大家都不會陌生,下面會大家從屬性、內部類、好玩的幾個方法入手,來簡單解析下Integer這個類。

屬性:

代表Integer邊界的最大值MAX_VALUE和最小值MIN_VALUE

MIN_VALUE = 0x80000000  MAX_VALUE = 0x7fffffff  眾所周知數值在電腦中以補碼形式存儲:  MIN_VALUE:  補碼:1000 0000 0000 0000 0000 0000 0000 0000  反碼:1111 1111 1111 1111 1111 1111 1111 1111 = 補碼 - 1 (最高位是符號位不能變哦)  原碼:1000 0000 0000 0000 0000 0000 0000 0000 = -2^31  MAX_VALUE:  源碼 = 反碼 = 補碼 :0111 1111 1111 1111 1111 1111 1111 1111 = 2^31 - 1  不太熟悉的小夥伴可能有點好奇:  MIN_VALUE -2^31  MAX_VALUE 2^31 - 1  這倆個怎麼相差1呢?是這樣的,當把符號位加入後為零的情況就出現了倆種  一種是 +0 一種是 -0,所以不能浪費啊,仔細看上面-2^31其實就是-0啦,是不是很巧妙!

VALUE 存儲Integer的數值

SIZE 存儲Integer是多少位(32位)

BYTES 就是說一個int是多少位元組(8 * 4)4位元組

上圖中屬性里還有一些char的數組,主要是用來方便後面方法的快速計算這裡就不一一介紹,後面會給出幾個例子。

內部類

IntegerCache:相信很多小夥伴從名字就能看出,這是個快取,那麼Integer為什麼要這個快取能?這個快取的作用是什麼呢?下面進行簡單的介紹。

IntegerCache:  三個屬性:  int low = -128;  int high; // 可從外部傳入 默認是127  Integer cache[];  然後有個靜態程式碼塊,在類載入的時候運行:    static {      // high value may be configured by property      int h = 127;      // 外部配置high,未配置默認127(上面的h)      String integerCacheHighPropValue =          sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");      if (integerCacheHighPropValue != null) {          try {              int i = parseInt(integerCacheHighPropValue);              i = Math.max(i, 127);              // 加上128個負數 最大不能超過Integer能表示的最大值              h = Math.min(i, Integer.MAX_VALUE - (-low) -1);          } catch( NumberFormatException nfe) {              // If the property cannot be parsed into an int, ignore it.          }      }      high = h;        cache = new Integer[(high - low) + 1];      int j = low;      for(int k = 0; k < cache.length; k++)          cache[k] = new Integer(j++);        // range [-128, 127] must be interned (JLS7 5.1.7)      assert IntegerCache.high >= 127;  }  由程式碼來看負數的範圍好像只能到-128    既然有快取那麼經典的例子就出現啦:  採用默認的high大小:  Integer i1 = 127;  Integer i2 = 127;  Integer i3 = 128;  Integer i4 = 128;  // 取快取了  System.out.println(i1 == i2);// true  // 沒得快取取  System.out.println(i3 == i4);// false

下面就開始介紹一些好玩的方法啦:

valueOf()

// 返回數值i包裝類型  publicstatic Integer valueOf(int i) {      // 判斷範圍看是否能從快取里拿      if (i >= IntegerCache.low && i <= IntegerCache.high)          return IntegerCache.cache[i + (-IntegerCache.low)];       // 快取里沒有的話直接建對象      return new Integer(i);  }  由此可見以下程式碼也成立:  Integer i1 = Integer.valueOf(127);  Integer i2 = Integer.valueOf(127);  Integer i3 = Integer.valueOf(128);  Integer i4 = Integer.valueOf(128);  // 取快取了  System.out.println(i1 == i2);// true  // 沒得快取取  System.out.println(i3 == i4);// false  請注意:下面這樣的肯定不行  Integer i1 = new Integer(127);  Integer i2 = new Integer(127);  i1 == i2 // false  很明顯是在new對象嘛,所以肯定是false咯!

getChars()

// 將int數字轉換放進一個字元數組  static void getChars(int i, int index, char[] buf) {    int q, r;    int charPos = index;    char sign = 0;    // 如果是負數則轉成正數 方便運算    if (i < 0) {        sign = '-';        i = -i;    }    // 為什麼這裡要區分大於65536的呢?    // 相對於除法運算電腦更喜歡乘法運算,當然如果能用加法最好不用乘除,影響性能,那用乘除法和這裡區分    // i的大小明顯沒啥關係啊,咋一看好像沒什麼關係,我們注意到在while循環里用的是除法i/100,前面提到    // 電腦更加喜歡性能高的乘法,所以這裡把i分塊是為了讓後面的i做乘法運算。那問題來了,為什麼不直接    // 做乘法運算呢?仔細看程式碼,發現這裡用的是 i - 10*(i/10)由於i是int類型會拋棄餘數,這樣減法得出i的個位數,從而換成char字元,    // 當然當i>=65536的時候是進行倆位一起轉換    //    // 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;        // 這裡看了DigitOnes和DigitTen數組你就會豁然開朗了下面貼出來        buf [--charPos] = DigitOnes[r];        buf [--charPos] = DigitTens[r];    }      // Fall thru to fast mode for smaller numbers    // assert(i <= 65536, i);    for (;;) {        // 這裡是做乘法運算2的19次方是52488  這裡相當於i * 52429/524288 這樣相當於i/10這個操作了        // 這裡們其實可以找出很多對 如 104858/1048576(2的10次方) 209716/2097152(2的21次方)而且這些式子得出結果的精度也差不多,        // 那麼現在就要考慮i的問題,前面已經說了電腦對乘法運算更加喜愛,所以這裡我們儘可能的讓i大,所以我們要儘可能的把與i相乘        // 的這個數(52429)縮小,但是精度要高一點,不然會有誤差。        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;    }  }  // 上面出現了這倆行程式碼:  buf [--charPos] = DigitOnes[r];  buf [--charPos] = DigitTens[r];  舉個例子比如:  buf [--charPos] = DigitOnes[67];  buf [--charPos] = DigitTens[67];    final static char [] DigitTens = {    '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',    '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',    '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',    '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',    '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',    '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',    '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',    '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',    '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',    '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',    } ;  final static char [] DigitOnes = {    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',    } ;    有沒有被驚艷到啊?

stringSize()

// 求十進位表示幾位數  static int stringSize(int x) {      for (int i=0; ; i++)          if (x <= sizeTable[i])              return i+1;  }  final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,                                        99999999, 999999999, Integer.MAX_VALUE };

highestOneBit()

// 取最高位的1其他全取0 如 14 = 1110 = 8+4+2=14  // highestOneBit(14) 會返回8 1000 因為只要最高位的1其他全0  public static int highestOneBit(int i) {      // HD, Figure 3-1      i |= (i >>  1);      i |= (i >>  2);      i |= (i >>  4);      i |= (i >>  8);      i |= (i >> 16);      //上面這段程式碼就是將你最高位的1往所有低位複製      //如 100000 運行完就是111111        // 11111 - 01111      return i - (i >>> 1);  }  類似的程式碼在HashMap里有個tableSizeFor(int cap)方法用來找  最接近cap且大於cap的2的冪的數值 如  cap = 11 返回 16 2^4  cap = 24 返回 32 2^5

和上面這個方法一對的

lowerOneBit()

    public static int lowestOneBit(int i) {          // HD, Section 2-1          return i & -i;      }      6 & -6 = 2      int有32位 前面的0自行腦補哈!      6 = 0000...110      -6 = 1111...010 // 電腦存的是補碼哈      &一下就是 0000....10 = 2 這就取到最低位的1 其他位全置零

numberOfLeadingZeros()

// 求一個數二進位的表示 前面有多少零  public static int numberOfLeadingZeros(int i) {      // HD, Figure 5-6      if (i == 0)          return 32;      int n = 1;      // 前16位為零的話 就剔除這16個      if (i >>> 16 == 0) { n += 16; i <<= 16; }       // 前8位為零的話 就剔除這8個      if (i >>> 24 == 0) { n +=  8; i <<=  8; }       // 前4位為零的話 就剔除這4個      if (i >>> 28 == 0) { n +=  4; i <<=  4; }       // 前2位為零的話 就剔除這2個      if (i >>> 30 == 0) { n +=  2; i <<=  2; }      // 最後一個      n -= i >>> 31;      return n;  }

最後留個作業:求一個數的二進位表示中1的個數,方法在下面給出了:

public static int bitCount(int i) {      // HD, Figure 5-2      i = i - ((i >>> 1) & 0x55555555);      i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);      i = (i + (i >>> 4)) & 0x0f0f0f0f;      i = i + (i >>> 8);      i = i + (i >>> 16);      return i & 0x3f;  }