原創作品,出自 “曉風殘月xj” 博客,歡迎轉載,轉載時請務必註明出處(http://blog.csdn.net/xiaofengcanyuexj)。
由於各種原因,可能存在諸多不足,歡迎斧正!
今天讀《Effective Java》,讀到“基本類型優於裝箱基本類型” ,其中那個Integer例子覺得不合適,於是看了Integer源碼,發現還真是有點問題,至少我的jdk1.7是有問題的。
Java是高度封裝基於JVM API的語言,和C++一個重要的區別就是不支持運算符重載。就我膚淺地理解,基本的運算操作+、-、*、/、==等對於開發者老說通常是不透明的,所以對於模糊的地方不好把握,對於裝飾器類型也就是通常意思的裝箱類型,如下:
int(4字節) | Integer |
byte(1字節) | Byte |
short(2字節) | Short |
long(8字節) | Long |
float(4字節) | Float |
double(8字節) | Double |
char(2字節) | Character |
boolean(未定) |
Boolean |
==對於裝箱類型是不好把握的。以Integer爲例,通常在[-128,127](其中127取決於JDK中的)系統變量,具體如下:
String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
由於比較簡單,直接上實例代碼的
/**
* @功能: Java測試類
* @authord: jin.xu
* @version: v1.0.0
* @see:
* @date: 2016/1/30 11:49
*/
public class Test {
public static void main(String[] args) {
Integer i=127;
Integer j=127;
if(j==i){
System.out.println("true");
}else{
System.out.println("false");
}
Integer k=128;
Integer t=128;
if(k==t){
System.out.println("true");
}else{
System.out.println("false");
}
}
}
輸入結果分別是:
true
false
具體原因應該說是jdk還不能說是JVM將小範圍的數值做了緩存,如int的[-128,127](其中128並不是一個比較準確的答案),new對象的時候不是直接在堆上創建,而是從常量池中讀取,避免頻繁創建對象。我們知道,在堆上創建對象是有系統開銷的,而池化技術可以在一定程度上解決這類問題,如內存池、線程池等。當然,像jdk這類直接選定數值的方法也是比較粗糙的,還好其中的integerCacheHighPropValue 變量可以針對不同機器作調整。具體直接貼jdk代碼的
/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/
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() {}
}
所以建議是對於裝箱類型,比較數值的時候最好直接使用equal()或者XXXValue()方法,避免使用運算符==。自己踩過或者躲過的坑,希望別人也不要踩。
最近空閒時間有看源代碼的習慣,如雅虎基於在線機器學習開源爬蟲anthelion和dubbo的