前面一篇的结尾,我们画了一张图,对Java的数据类型进行了分类。其中,有8种基本数据类型,还有引用类型。我们先来看看下面这段程序。
package demo3;
/**
* create by Anthony on 2017/10/28
*/
public class ForTest {
public static void main(String args[]){
//基础数据类型,一共8种
byte b = 10;
short s = 11;
int i = 16;
long l = 10L;
float f = 234.5f;
double d = 123.4;
char c = 'A';
boolean bool = true;
//Java 引用类型 或者叫类 对象 类型
Byte myByte = new Byte("10"); // 分配内存空间
Short myShort = new Short(s); // 编辑器提示不需要装箱
Integer myInteger = Integer.valueOf(i);
Long myLong;
Float myFloat;
Double myDouble;
Character myCharacter;
Boolean myBoolean;
}
}
我们不需要运行这段代码,前面我们知道8种基本数据类型的声明和初始化操作。但是看第二段代码,发现有和八种基本数据类型一一对应的类。先不管它们是什么和前面有什么关系,这里先看看IDE中的一个警告提示。
第一句说,没必要的装箱。下面一段详细解释了,在Java5和之后版本,显示手动把基本数据类型装箱是不需要了。那么问题来了,这么出现了一个新的概念,装箱,既然有装箱,肯定有拆箱的概念。所以,我们先学会基本的装箱和拆箱的概念。
1.什么是装箱和拆箱
在回答这个问题,之前,我们可以网上查阅资料。在Java5版本之前,如果需要创建一个值为8的Integer对象,必须要这样写代码:
Integer i = new Integer(8);
而在Java5之后,提供了自动装箱的特性,如果要创建一个值为8的Integer对象,变成了这样写代码:
Integer i = 8;
这个过程中会自动根据数值创建对应的 Integer对象,这就是装箱。那什么是拆箱呢?顾名思义,跟装箱对应,就是自动将包装器类型转换为基本数据类型:
Integer i = 8; //装箱
int n = i; //拆箱
具体到一种类型来讲,int是基本数据类型,Integer是int的包装器类。我们平时习惯的基本数据类型的声明和初始化就是利用了自动拆箱的原理。所以,结论就是:装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。
2.看int包装器类的valueof方法源代码
对应的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.cache()方法,返回已经存在的对象引用。如果不在范围就新建一个对象,看到new就想起新开辟内存空间去存储对象的值。那么这个范围是什么呢?按住ctrl键,点击IntegerCache,看源码。
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() {}
}
看代码和这个方法前面的注释文字,我们知道这个方法就是给范围在-128到127内的int类型的基础类型进行自动包装。大概对这个范围有印象就可以。下面这道笔试题就是考察这个知识点。
public class Main {
public static void main(String[] args) {
Double i1 = 100.0;
Double i2 = 100.0;
Double i3 = 200.0;
Double i4 = 200.0;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}
如果你知道范围在-128到127会返回内存中存在的引用,超过127就会采用new一个对象,而new是需要新开辟内存空间的。所以上面的==其实就是比较内存地址,而不是比较数值大小。所以i1和i2两个内存地址一样,输出true。但是i3和i4大于127,这个自动装箱走了new这个代码,新开辟了内存,所以两个内存地址肯定不同。