Java数据类型分为两大类:基本数据类型 和 引用数据类型
基本数据类型 (8个):
- 整型:byte short int long 分别是1 2 4 8 字节
- 浮点型:float double 分别是4 8字节
- 字符型:char
- 布尔型:boolean
引用数据类型
- 类对象: Object obj = new Object();
- 数组:包括对象数组 和 基本数据类型数组如 int[] arr;
类型区别
引用数据类型所对应的类型都是Object的(子类)对象; arr instanceof Object == true
基本数据类型不是对象类型
初始化区别
基本数据类型的初始化值为 整型 0、浮点型0.0、字符型char c = (char) 0、布尔型 false
引用数据类型则为null
整型的进制表示法
二进制: 有前缀0b/0B,如 0b1001/0B1001
八进制:有前缀0, 如01276
十六进制:有前缀0x/0X,如0xCA2E/0XCA2E
自动类型转换
二元操作时,数值类型会按照下面的逻辑进行自动类型转换
(byte short char) > int > long -> float > double + 字符串连接符 > string
自动装箱 自动拆箱
当代码发现需要将常量复制给包装类型时,采取什么手段进行自动装箱呢?
当代码需要对包装类型的值进行相关计算时,采取什么手段进行自动拆箱呢?
我们知道这两个自动过程其实是在编译期完成的,那么就可以对class反编译来查看编译器的处理过程。例如:
请先看java源文件,及javap反编译的class代码片段
public class WrapperTest {
public void testJavap(){
Integer a = 100; // 将数字100赋值给变量a, jdk1.5之前这么写会报错
a++ ; // ++ 操作只能作用于基本数据类型
}
}
$ javap -c WrapperTest.class
Compiled from "WrapperTest.java"
public class com.neo.java.dataType.WrapperTest {
public com.neo.java.dataType.WrapperTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void testJavap();
Code:
0: bipush 100
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: aload_1
7: astore_2
8: aload_1
9: invokevirtual #3 // Method java/lang/Integer.intValue:()I
12: iconst_1
13: iadd
14: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
17: dup
18: astore_1
19: astore_3
20: aload_2
21: pop
22: return
}
从反编译文件可以看出来。Integer a = 100; 自动装箱时使用了java.lang.Integer.valueOf(a) 方法。
a++ 时 先调用Integer.intValue() 方法获取包装类型的值,这是自动拆箱。然后执行add操作,再执行装箱。
我们再来看看Integer.valueOf的实现方法
发现Integer里维护了一个int数值,这个数组里的值的范围是 -128 ~ 127 也就是说当给变量a赋值在这个范围之内的时候,直接返回一个数组元素。也就是说该范围内的自动装箱的变量都是指向同一片内存区域的。只有操作这个范围,才会使用new操作符。才会新申请内存地址。这个在变量 == 判断的时候需要格外注意