本文结构如下:
- 什么是基本数据类型
- 什么是包装类
- 两者的区别以及使用场景
- 什么是自动装箱拆箱
- 整型常量池
1.什么是基本数据类型
java 中的对象很多都是朝生夕死的(gc回收),所以一直放在堆中不是很高效。因此为方便基本类型的数据计算,java创造了八种基本数据类型:整型byte, short, int, long, 浮点型double, float, 字符型char, 布尔型boolean
基本数据类型 | 默认值 | 包装类 |
byte | 0 | Byte |
short | 0 | Short |
int | 0 | Integer |
long | 0L | Long |
float | 0.0f | Float |
double | 0.0d | Double |
char | ‘\u0000’(其实就是0) | Character |
boolean | false | Boolean |
1.1 整型:
byte属于Java中的整型,长度为1字节8bit,取值10000000(-128)到 01111111(127),变量初始化默认值为0;
short属于Java中的整型,长度为2字节16bit,取值10000000 00000000(-32768)到 01111111 11111111(32767),变量初始化默认值为0;
int属于Java中的整型,长度为4字节32bit,取值-2^31 (-2,147,483,648)到 2^31-1(2,147,483,647),变量初始化默认值为0;
long属于Java中的整型,长度为8字节64bit,取值-2^63 (-9,223,372,036,854,775,808)到 2^63-1(9,223,372,036,854,775,8087),变量初始化默认值为0或0L。
1.2 浮点型:
java 的浮点类型都依据 IEEE 754 标准。IEEE 754 定义了32 位和 64 位双精度两种浮点二进制小数标准。
IEEE 754 用科学记数法以底数为 2 的小数来表示浮点数。32 位浮点数用 1 位表示数字的符号,用 8 位来表示指数,用 23 位来表示尾数,即小数部分。作为有符号整数的指数可以有正负之分。小数部分用二进制(底数 2 )小数来表示。对于64 位双精度浮点数,用 1 位表示数字的符号,用 11 位表示指数,52 位表示尾数。
浮点运算很少是精确的,只要是超过精度能表示的范围就会产生误差。往往产生误差不是 因为数的大小,而是因为数的精度。因此,产生的结果接近但不等于想要的结果。尤其在使用 float 和 double 作精确运 算的时候要特别小心。
浮点型精确性验证可参考这篇文章:https://zhidao.baidu.com/question/692123529504139004.html
1.3 字符型:
char属于java中的字符型,占2字节16bit,可以赋值单字符以及整型数值。
1.4 布尔值:
在JVM中并没有提供boolean专用的字节码指令,而boolean类型数据在经过编译后在JVM中会通过int类型来表示,此时boolean数据4字节32位,而boolean数组将会被编码成Java虚拟机的byte数组,此时每个boolean数据1字节占8bit。
布尔值仅有两个值true, false,变量初始化默认值false
1.5 基本数据类型转换注意点:
低精度数据类型可直接转高精度数据类型,高精度数据类型得强转低精度数据类型,且会造成数据失真。
int a = 2147483647;
long b = a;//低精度可直接转高精度
b++;
int c = (int) b;//高精度强转低精度,数据失真
例如:正方形也属于长方形,但长方形转为正方形就得切去部分面积。
2.什么是包装类
Java 是一个面相对象的编程语言,基本类型并不具有对象的性质,为了让基本类型也具有对象的特征,就出现了包装类型,它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。
2.1 特点
包装类统一继承抽象类Number,并且实现了Comparable接口
包装类都是final,而且成员变量都是static final
2.2 构造方式
1)通过直接赋值 Integer i=1;
2)构造器 Integer i=new Integer(1);
3)静态工厂valueOf方法 Integer i=Integer.valueOf(1);
3. 两者的区别以及使用场景
3.1 区别:
包装类可以为null,而基本类型不行。
基本类型有默认值,包装类默认都为null。
基本数据类型存在栈中,包装类存在堆中需要通过地址引用,基本数据类型使用效率更高。
3.2 对象属性必须使用包装类型
数据库的查询结果可能是 null,如果对象属性使用基本类型的话,把null返回给基本数据就会报错。
举例:Student对象类中的成绩score属性值为0,如果成绩是基本类型,可能是考了0分,可能是没考,会有歧义。但如果成绩是包装类型,那说明是考了0分,没考值是null。
3.3 泛型必须使用包装类型
因为泛型在编译时会进行类型擦除,最后只保留原始类型,而原始类型只能是 Object 类及其子类——基本类型是个特例。
3.4 基本类型比包装类型高效
基本类型在栈中直接存储的具体数值,而包装类型则存储的是堆中的引用。包装类型需要占用更多的内存空间。假如没有基本类型的话,对于数值这类经常使用到的数据来说,每次都要通过 new 一个包装类型就显得非常笨重。
3.5 两个包装类型的值可以相同,但却不一定相等
总结:对象类及泛型必须使用包装类型,其他场景比如局部变量时,使用基本数据类型更高效。
3.6 方法参数为包装类型则允许空值
接口参数如果是包装类,不传就会报错。而如果接口参数是基本类型,参数不传不会报错,因为基本类型是有默认值的。
4. 什么是自动装箱拆箱
既然有了基本类型和包装类型,肯定有些时候要在它们之间进行转换。把基本类型转换成包装类型的过程叫做装箱(boxing)。反之,把包装类型转换成基本类型的过程叫做拆箱(unboxing)。
Java SE5 为了减少开发人员的工作,提供了自动装箱与自动拆箱的功能。
如下两行基本数据类型和包装类的转换:
Integer chenmo = 10;
//实际执行的代码:Integer chenmo = Integer.valueOf(10);
int wanger = chenmo;
//实际执行的代码:int wanger = chenmo.intValue();
自动装箱是通过 Integer.valueOf() 完成的;自动拆箱是通过 Integer.intValue() 完成的。
5. 整型常量池
先看两组判断:
Integer c = 100;
Integer d = 100;
System.out.println(c == d);//true
Integer c = 200;
Integer d = 200;
System.out.println(c == d);//false
输出为什么会有不同,我们看一下Integer赋值方法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缓存池,当需要进行自动装箱时,如果数字在 -128 至 127 之间时,会直接使用缓存中的对象,而不是重新创建一个对象。IntegerCache的源码如下:
/**
* 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() {}
}
有不足之处请多指教~