基本类型

Java 内置 8 种基本数据类型:

  • 4 种整数型
    • byte —— 1 字节, 有符号数
    • short—— 2 字节, 有符号数
    • int —— 4 字节, 有符号数
    • long —— 8 字节, 有符号数
  • 2 种浮点型
    • float —— 4 字节, 单精度浮点数
    • double —— 8 字节, 双精度浮点数
  • 1 种字符型
    • char —— 2 字节, Unicode 字符, 无符号数, 最小值 ‘\u0000’, 最大值 ‘\uffff’
  • 1 种布尔型
    • boolean

4 种整数型都是有符号数
char 是无符号数
整数型默认为 int 类型
浮点数默认为 double 类型

类型转换

Java 允许把任何基本数据类型通过自动类型转换或强制类型转换而转换成别的基本数据类型 (除了布尔类型, 布尔类型不允许进行类型转换).
image.png
容量小的数据类型可以自动转换为容量大的数据类型 (容量指的是表数范围, 不是字节大小).
byte, short, char 在运算时会转换成 int, 结果也是 int.

包装类型

基本类型具有包装类型, 使得可以在堆中创建非基本对象, 包装类内部封装了对应的基本类型.
包装类都是不可变类, 不可变使程序更加简单安全.

享元模式

IntegerCache 是 Integer 的私有内部类, 在初始化的时候创建并保存了 -128 ~ 127 的对应的 Integer 对象, 这样 -128 ~ 127 范围的就不用重复创建了, 直接取 IntegerCache 内的就可以了. 这样节省了内存空间. 又因为 Integer 是不可变的, 可以安全的共享. 这种设计思路叫做享元模式 (Flyweight, 共享的轻量级元素).

image.png

  1. Integer i1 = 127;
  2. Integer i2 = 127;
  3. Integer i3 = new Integer(127);
  4. assert i1 == i2; // i1, i2 是同一个 IntegerCache 中的对象
  5. assert i1 != i3; // i1 是 IntegerCache 中的对象, i3 是 new 出来, 是不同的对象
  6. Integer i4 = 128;
  7. Integer i5 = 128;
  8. assert i4 != i5; // i4, i5 是分别 new 出来的, 是不同的对象

char 类型

在 Java 内部用 Unicode 处理字符, 编码格式为 UTF-16BE.
UTF-16 使用 2 或 4 个字节表示一个字符, Unicode 编号在 65536 以内的占 2 个字节, 超出的占 4 个字节.
char 本质上是一个固定占用 2 个字节的无符号正整数, 这个正整数对应 Unicode 编号, 用于表示那个 Unicode 编号对应的字符.

由于 char 固定占用 2 个字节, 那 4 个字节的字符怎么表示?
使用 2 个 char. 相关类有 Character, String.

int 可以表示所有的 Unicode, 所以 Character 类中的方法有 char 和 int 的重载版本. 可以说 Character 面向的不是 char, 而是 Unicode

char c = '马'
char c = 39532
char c = 0x9a6c
char c = '\u9a6c'

算数运算

位移操作符只能用来处理整数类型.
如果对 char, byte, short 类型进行位移操作, 那么在位移前, 会被转换为 int 类型, 得到的结果也是 int 类型.
如果对 long 类型进行位移操作, 得到的结果也是 long 类型.

System.out.println(2.0 - 1.1);        // 0.8999999999999999
long n1 = 24 * 60 * 60 * 1000 * 1000;    // 500654080 溢出
// 这个计算完全是以 int 运算来执行的, 在运算完成后, 其结果才被提升为 long

long n2 = 24L * 60 * 60 * 1000 * 1000;    // 86400000000 没溢出
System.out.println((int)(char)(byte)-1);    // 65535

// 转换过程: ffffffff (int) -> 直接截断高位 ff (byte) -> 符号拓展 ffff (char) -> 0 拓展 0000ffff (int)

从宽到窄, 直接截断高位 从窄到宽, 看原类型是什么

  • 原类型是有符号类型进行符号拓展
  • 原类型是无符号类型进行 0 拓展
int x = 12;
int y = 34;
x = x ^ y;
y = x ^ y;
x = x ^ y;
System.out.println(x);    // 34
System.out.println(y);    // 12

x ^ x = 0;
x ^ 0 = x;
int i1 = 0x1fffffff;        // 536870911
int i2 = 0xffffffff;        // -1

0x 前缀表示十六进制数 不同于十进制, 八进制和十六进制表示的是补码 十进制数通过正负号表示正负数 十六进制数通过最高位表示正负数