下面是八种基本数据类型以及对应的包装类型,其他的都是引用数据类型。
数据类型 | 包装类型 | 占用字节 |
---|---|---|
byte | Byte | 1 |
short | Short | 2 |
int | Integer | 4 |
long | Long | 8 |
float | Float | 4 |
double | Double | 8 |
char | Character | 2 |
boolean | Boolean | true/false |
1.为什么有基本数据类型还要有包装数据类型?使用包装类型的好处是什么?
- 在Java中,我们知道凡是new的都会在堆空间中分配一定的内存地址,如果我么们频繁的使用Integer、Byte等等,那么会频繁的使用堆空间,因此对垃圾回收造成一定的困难,影响了使用的的效率;基本数据类型只是在栈中创建、使用、以及销毁,这样节约了空间以及效率提供。
- 而java语言又是面向对象语言。万事万物皆对象。但是在java中,基本数据类型又不是面向对象的,因此该基本数据类型不具备面向对象的特征。为了使得基本数据类型具备面向对象的特征,那么采用将基本数据类型进行包装,使得具备面向对象的特征。为其提供基本属性以及方法,使得可以对其他对象方便使用。例如字符串转换为基本数据类型,
1.某些方法必须使用对象作为参数,因此需要使用包装类
2.包装类提供了更强大的方法和功能
3方便其他对象与基本类型之间转换
基本数据类型与包装类的对比?
类别\类型 | 基本数据类型 | 包装数据类型 |
---|---|---|
默认值 | 0或者false | null |
存储位置 | 栈中 | 堆中 |
使用方式 | 直接声明 | 直接声明或者是使用new来分配内存地址 |
2.包装类型与基本数据类型之间是如何转换的,以Int和Integer为例子?
- 分析Integer a=10;是如何进行装箱的?
首先会在编译阶段将调用Integer的valueOf方法,将Integer a=10进行装箱操作。下面是进行装箱操作的代码以及Integer a=10;的反编译后的代码。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
public static void main(java.lang.String[]);
Code:
0: bipush 10
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: return
}
- 那么int b=a;是如何将包装类型转换为int类型尼?
首先会在编译期间调用intValue方法将拆箱操作返回包装类的具体值。以下代码是int b=a的拆箱调用的intValue方法以及反编译后的代码信息。
public int intValue() {
return value;
}
public static void main(java.lang.String[]);
Code:
0: bipush 10
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: aload_1
7: invokevirtual #3 // Method java/lang/Integer.intValue:()I
10: istore_2
11: return
}
通过以上的分析可以看出,java在进行拆箱以及装箱过程中调用不同的方法来实现的,会在编译阶段就确定出具体的值,而不会是在运行时确定值。那么是否和String的字符串常量池类似哪?
3.在2.1的代码中看到IntegerCache表示的是什么
这个表示的是缓存类,该类中保存了包装类Integer的缓存值,那么分析可见,如果Integer a的值在-128到127时,在进行包装时,就直接获取值;如果不在这其中那么直接new Integer(a)的值
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() {}
}
4。分析==以及equals方法在包装类中的使用?
首先包装类对Object类中的equals方法进行了重写,因此不想Object类中的equals方法内部使用的是==来比较。以下代码则为Integer中的equals方法.
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
下图是分别分析a、b、c的内存分布图。
- 当Integer a=在-128到127中时,a指向的是常量池中的值。
- 当Integer b=500时,底层会调用ValueOf方法对其装箱,但是该值不在缓存值的范围内,因此new Integer(500)在堆中分配内存空间,所以b指向的时堆中的地址。
- 当Integer c=new Integer(500)时,直接在堆内存中分配内存空间。所以c指向的是新的内存空间。(凡是new的都会在堆中分配内存空间)。
== 总结 ==
1.int和int用“= =”比较时,返回true,没有equals方法,因此不能使用equals方法
2.int和integer用= =比较时,integer会自动拆箱,所以返回true
int和new Integer()用= =比较时,integer会自动拆箱,所以返回true
3.integer和integer用= =比较时,如果值的范围在-128到127时,Integer直接从缓存中获得该值,所以直接返回true,如果不在此范围那么,那么会调用new interger()方法,所以地址值不同(返回false)
4.integer和new Integer()用= =比较时,不管Integer的值是在-128到127之间还是不在其缓存池值中,都不会分配不同的地址值,比较内存地址不同,所以为false,equals为true
5.new Integer()和new Integer()用= =比较时,比较内存地址不同(凡是new都会在堆中分配内存空间因此不会相等),所以为false,equals为true
*[注释]:
- == 比较基本数据类型时:比较的是值
- == 比较引用数据类型时:比较的时引用类型的地址值
- equals方法时Object类中的方法,其引用的是==号,所以和= =用法相同,但是如果对其equals重写,那么就按照重写的规则比较。例如String、Integer类