### Integer
> 本文源碼基于JDK8
Integer也是我們經常使用的工具類、包裝類,此文主要用于記錄學習筆記,主要從源碼角度深入了解一下。
```
public final class Integer extends Number implements Comparable<Integer> {
// 2147483647
public static final int MIN_VALUE = 0x80000000;
// -2147483648
public static final int MAX_VALUE = 0x7fffffff;
// 獲取基本類型int類型是class
public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
}
```
說明:Integer.TYPE == int.class // true
* 繼承Number類
Number類中只有構造方法和幾個抽象方法:

### 構造方法
```
public Integer(int value) {
this.value = value;
}
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
```
### 自動裝箱和自動拆箱
JDK1.5之后,java提供了自動裝箱和自動拆箱的功能,下面從源碼角度分析下Integer的裝箱:
```
package com.quancheng;
public class ClassTest {
public static void main(String[] args) throws InterruptedException {
Integer num = 10;
}
}
```
通過javap -v ClassTest.class查看字節碼,可以看出自動裝箱實際是JVM編譯器幫我們做的工作,調用的是Integer.valueOf\(\)方法
```
public static void main(java.lang.String[]) throws java.lang.InterruptedException;
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=2, args_size=1
0: bipush 10
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: return
```
分析到這里可以看出,實際上Integer a = 100 等價于Integer a = Integer.valueOf\(100\);只不過這個工作是JVM幫我們做的;
自動拆箱:
```
public static void main(String[] args) throws InterruptedException {
int num = new Integer(11);
}
```
對應的字節碼指令:
```
public static void main(java.lang.String[]) throws java.lang.InterruptedException;
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=2, args_size=1
0: new #2 // class java/lang/Integer
3: dup
4: bipush 11
6: invokespecial #3 // Method java/lang/Integer."<init>":(I)V
9: invokevirtual #4 // Method java/lang/Integer.intValue:()I
12: istore_1
13: return
```
通過分析可以發現,自動拆箱實際是編譯器調用了Integer.intValue\(\)的方法完成的轉換
### 重點方法
* valueOf方法
```
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
```
IntegerCache是一個靜態內部類,主要用于緩存low - 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) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
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;
}
private IntegerCache() {}
}
```
上面的源碼中可以看出IntegerCache有三個被final修飾的靜態filed外加一個靜態塊和一個私有的構造器;很簡單很普通的一個類,被緩存的包裝類就介于low - high之間,low的值已經寫死-128,而high的值由你的虛擬機決定sun.misc.VM.getSavedProperty\("java.lang.Integer.IntegerCache.high"\),既然是一個參數也就意味著你可以動態設置,具體怎么設置自行百度。然后在循環中將low - high之間數字的裝箱后方法cache\[\]這個Integer類型的數組中。這樣就完成了緩存
在日常編碼中,我們需要注意Integer緩存的問題
```
Integer a = 100;
Integer b = 100;
Integer f = Integer.valueOf(100);
Integer c = 200;
Integer d = 200;
System.out.println(a == b);//true
System.err.println(a == f); // true
System.out.println(c == d);//false
```
* stringSize\(int x\)
這個方法很有意思,我覺得可以單獨看看這個方法,主要作用就是判斷一個數字的位數,但是運用的非常巧妙
```
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, Integer.MAX_VALUE };
// Requires positive x
static int stringSize(int x) {
for (int i=0; ; i++)
if (x <= sizeTable[i])
return i+1;
}
```
* equals\(Object obj\)
需要注意的是Integer也重寫了equals\(Object obj\),故若比較的值類型都是Integer時,equals\(\)和==作用是相同的
```
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
```
```
我們可以寫個例子測試下:
Integer num = new Integer(999);
System.err.println(num ==999);
public static void main(java.lang.String[]) throws java.lang.InterruptedException;
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=2, args_size=1
0: new #2 // class java/lang/Integer
3: dup
4: sipush 999
7: invokespecial #3 // Method java/lang/Integer."<init>":(I)V
10: astore_1
11: getstatic #4 // Field java/lang/System.err:Ljava/io/PrintStream;
14: aload_1
15: invokevirtual #5 // Method java/lang/Integer.intValue:()I
18: sipush 999
21: if_icmpne 28
24: iconst_1
25: goto 29
28: iconst_0
29: invokevirtual #6 // Method java/io/PrintStream.println:(Z)V
32: return
```
可以看出實際上是先拆箱再比較值
### 總結
* Integer i1=40;Java在編譯的時候會直接將代碼封裝成Integer
* Integer i1=Integer.valueOf\(40\);,從而使用常量池中的對象
* Integer i1 = new Integer\(40\);這種情況下會創建新的對象
* Integer的toString方法分成了兩部分進行處理,大于等于65536和小于65536的部分
### Integer有趣示例
```
Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);
System.out.println("i1=i2 " + (i1 == i2));
System.out.println("i1=i2+i3 " + (i1 == i2 + i3));
System.out.println("i1=i4 " + (i1 == i4));
System.out.println("i4=i5 " + (i4 == i5));
System.out.println("i4=i5+i6 " + (i4 == i5 + i6));
System.out.println("40=i5+i6 " + (40 == i5 + i6));
output==>
i1=i2 true
i1=i2+i3 true
i1=i4 false
i4=i5 false
i4=i5+i6 true
40=i5+i6 true
```
解釋:語句i4 == i5 + i6,因為+這個操作符不適用于Integer對象,首先i5和i6進行自動拆箱操作,進行數值相加,即i4 == 40。然后Integer對象無法與數值進行直接比較,所以i4自動拆箱轉為int值40,最終這條語句轉為40 == 40進行數值比較
- java演變
- JDK各個版本的新特性
- JDK1.5新特性
- JDK1.6新特性
- JDK1.7新特性
- JDK1.8新特性
- JAVA基礎
- 面向對象特性
- 多態
- 方法重載
- 方法重寫
- class
- 常量
- 訪問修飾符
- 類加載路徑
- java-equals
- 局部類
- java-hashCode
- Java類初始化順序
- java-clone方法
- JAVA對象實例化的方法
- 基礎部分
- JAVA基礎特性
- JAVA關鍵字
- javabean
- static
- 日期相關
- final
- interface
- 函數式接口
- JAVA異常
- 異常屏蔽
- try-with-resource資源泄露
- JAVA引用
- WeakReference
- SoftReference
- PhantomReference
- 位運算符
- try-with-resource語法糖
- JDK冷知識
- JAVA包裝類
- JAVA基本類型與包裝類
- java.lang.Boolean
- java.lang.Integer
- java.lang.Byte
- java.lang.Short
- java.lang.Long
- java.lang.Float
- java.lang.Double
- java.lang.Character
- 日期相關
- TemporalAdjusters
- String
- 字符串常量池
- String拼接
- String編譯期優化
- StringBuilder&StringBuffer
- intern
- 注解
- java標準注解
- 內置注解
- 元注解
- 自定義注解
- 注解處理器
- JVM注解
- Java8 Annotation新特性
- 反射-Reflective
- Reflection
- Class
- Constructor
- Method
- javabean-property
- MethodHandles
- 泛型
- 類型擦除
- bridge-method
- Accessor&Mutator方法
- enum
- JAVA數組
- finalize方法
- JAR文件
- JAVA高級編程
- CORBA
- JMX
- SPI
- Java SPI使用約定
- ServiceLoader
- 實際應用
- IO
- 工具類
- JDK常用工具類
- Objects
- System
- Optional
- Throwable
- Collections
- Array
- Arrays
- System
- Unsafe
- Number
- ClassLoader
- Runtime
- Object
- Comparator
- VarHandle
- 數據結構
- 棧-Stack
- 隊列(Queue)
- Deque
- PriorityQueue
- BlockingQueue
- SynchronousQueue
- ArrayBlockingQueue
- LinkedBlockingQueue
- PriorityBlockingQueue
- ConcurrentLinkedQueue
- 列表
- 迭代器
- KV鍵值對數據類型
- HashMap
- TreeMap
- Hash沖突
- ConcurrentHashMap
- JDK1.7 ConcurrentHashMap結構
- jdk7&jdk8區別
- 集合
- Vector
- Stack
- HashSet
- TreeSet
- ArrayList
- LinkedList
- ArrayList && LinkedList相互轉換
- 線程安全的集合類
- 集合類遍歷性能
- 并發容器
- CopyOnWriteArrayList
- ConcurrentHashMap
- 同步容器
- BitMap
- BloomFilter
- SkipList
- 設計模式
- 設計模式六大原則
- 單例模式
- 代理模式
- 靜態代理
- 動態代理
- JDK動態代理
- cglib動態代理
- spring aop
- 策略模式
- SpringAOP策略模式的運用
- 生產者消費者模式
- 迭代器模式
- 函數式編程
- 方法引用
- 性能問題
- Lambda
- Lambda類型檢查
- Stream
- findFirst和findAny
- reduce
- 原始類型流特化
- 無限流
- 收集器
- 并行流
- AOP
- 靜態織入
- aspect
- aspect的定義
- AspectJ與SpringAOP
- 動態織入
- 靜態代理
- 動態代理
- JDK動態代理
- CGLib動態代理
- Spring AOP
- SpringAOP五種通知類型
- @Before
- @AfterReturning
- @AfterThrowing
- @After
- @Around
- Aspect優先級
- SpringAOP切點表達式
- within
- execution
- 嵌套調用
- 系統優化與重構
- 重疊構造器模式
- 工具類構造器優化
- 常見面試題
- new Object()到底占用幾個字節
- 訪問修飾符
- cloneable接口實現原理
- 異常分類以及處理機制
- wait和sleep的區別
- 數組在內存中如何分配
- 類加載為什么要使用雙親委派模式,有沒有什么場景是打破了這個模式
- 類的實例化順序
- 附錄
- JAVA術語
- FAQ
- 墨菲定律
- 康威定律
- 軟件設計原則
- 阿姆達爾定律
- 字節碼工具
- OSGI