1. 数据类型
- 为什么会有基本数据类型
- 在java中new一个对象是存储在堆里的,对于我们经常操作的数据类型,每次创建对象这样太消耗资源,因此java提供了8个基本数据类型,存储在栈里。用起来更方便。
- 有了基本数据类型为什么还要有包装类型
- java是一个面向对象的编程语言,基本类型并不具有对象的性质,为了让基本类型也具有对象的特性,就出现了包装类型,它将基本类型包装起来,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。
- 当需要往集合(如ArrayList)中存放数据时,基本类型是放不进去的,因为容器都是装object的,这时就需要包装类型了。
2. 基本类型和包装类型的区别
- 声明方式不同:基本类型不使用new关键字,而包装类型需要使用new关键字来在堆中分配存储空间
- 存储方式及位置不同:基本类型是直接将变量值存储在栈中,而包装类型是将对象放在堆中,然后通过引用来使用
- 初始值不同:基本类型的初始值如int为0,boolean为false,而包装类型的初始值为null
- 使用方式不同:基本类型直接赋值直接使用就好,而包装类型在集合如Collection、Map时会使用到
3. 数据基础知识回顾
计算机中都是使用二进制的补码进行运算的,首先,我们知道1字节=8bit,那么8bit可以表示的数字范围是[-128,127]。注意首位的1表示负数,0表示正数
1000 0000:-128 或 -2^7-1
0111 1111: 127 或 2^7-1
4. 类型转换的条件
- 转换前的数据类型的位数低于转换后的数据类型
byte,short,char—> int —> long—> float —> double
- 不能对boolean进行类型转换
- 不能把对象类型转换成不相关的对象
- 由大到小会丢失精度:在把容量大的类型转换为容量小的类型时必须使用强制类型转换
- 条件是转换的数据类型必须是兼容的。
- 格式:(type)value type是要强制类型转换后的数据类型
- 转换过程中可能导致溢出或损失精度,例如:
int i =128;
byte b = (byte)i;//-128
// 因为 byte 类型是 8 位,最大值为127,所以当 int 强制转换为 byte 类型时,值 128 时候就会导致溢出。
- 浮点数到整数的转换是通过舍弃小数得到,而不是四舍五入,例如:
(int)23.7 == 23;
(int)-45.89f == -45
5. 基本类型和包装类对应关系
8种基本数据类型对应包装类:可以看到除了int和char类型,其它都是首字母大写
| 基本数据类型 | 包装类 |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Character |
| boolean | Boolean |
6. 自动装箱和拆箱 autoBoxing and unBoxing
- 定义:
- 装箱就是自动将基本数据类型转为包装类型 Integer integer = Integer.valueOf(1)
- 拆箱就是自动将包装类型转为基本数据类型 int i = integer.intValue()
- 装箱的过程会创建对应的对象,这个会消耗内存,所以装箱的过程会增加内存的消耗,影响性能
- int类型
public static Integer valueOf(int i) {
return i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];
}
- 如果i小于-128或者大于等于128,就创建一个Integer对象,否则执行SMALL_VALUES[i + 128]
private static final Integer[] SMALL_VALUES = new Integer[256];
- SMALL_VALUES本来已经被创建好,也就是说在i >= 128 || i < -128是会创建不同的对象,在i < 128 && i >= -128会根据i的值返回已经创建好的指定的对象
- 在Double里面的做法很直接,就是直接创建一个对象,所以每次创建的对象都不一样。
public static Double valueOf(double d) {
return new Double(d);
}
public class Main {
public static void main(String[] args) {
Boolean i1 = false;
Boolean i2 = false;
Boolean i3 = true;
Boolean i4 = true;
System.out.println(i1==i2);//true
System.out.println(i3==i4);//true
}
}
public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}
可以看到返回的都是true,也就是它们执行valueOf返回的都是相同的对象
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false)
可以看到它并没有创建对象,因为在内部已经提前创建好两个对象,因为它只有两种情况,这样也是为了避免重复创建太多的对象
7. 类型间转换
- 基本数据类型转String类`
- String类的valueOf()方法:String fs = String.valueOf(2.34f);
- 更直接的方式5+""
- String类转基本数据类型
- 通过包装类的构造器实现
int a = new Integer("1"); int a = new Integer("aa"); // NumberFormatException - 调用包装类的转换静态方法
Integer a = Integer.parseInt("1");
- 通过包装类的构造器实现
- 包装类转String类型
- 包装类对象的toString方法
Integer a = new Integer(1); String str = a.toString(); - 包装类的toString方法
String s = Integer.toString(1);
- 包装类对象的toString方法
- String类转包装类
- 通过字符串参数
Integer a = new Integer("1");
- 通过字符串参数
8. Integer 和 int 之间的比较
int 和 Integer在进行比较的时候,Integer会进行拆箱,转为int值与int进行比较
Integer i1 = 1;
int i2 = 1;
System.out.println(i1 == i2); //true
Integer i3 = 128;
int i4 = 128;
System.out.println(i2 == i3); //true
9. Integer与Integer比较
Integer 直接赋值的时候会进行自动装箱
- -128<= x<=127的整数,将会直接缓存在IntegerCache中,那么当赋值在这个区间的时候,不会创建新的Integer对象,而是从缓存中获取已经创建好的Integer对象
- 大于这个范围的时候,直接new Integer来创建Integer对象
Integer i1 = 1;
Integer i2 = 1;
System.out.println(i1 == i2); // true
Integer i3 = 128;
Integer i4 = 128;
System.out.println(i3 == i4); // false
Integer i5 = new Integer(127);
Integer i6 = 127;
System.out.println(i5 == i6); // false
// i6进行自动装箱使用的是IntegerCache中的对象,i5是自己new的对象,地址不同
Integer i7 = new Integer(128);
Integer i8 = 128;
System.out.println(i7 == i8); // false
// i7,i8都是自己创建的新的对象,在堆中的地址不同