在计算机中,数据是以二进制的形式表示、存储和处理的。它的基本单位是位(b),每位表示一个二进制数,即 0 或 1。而在编程语言中,存储 1 位的数据包含的信息太少,往往没有意义,所以人们将 8 个连续的位看成一组,成为一个字节(B),然后用字节作为内存的最小寻址单元,即内存的基本存储单位是字节。

  1. 数据是多种多样的,不同的数据需要的存储单元也不尽相同。而想要正确的访问数据,不仅需要知道内存单元的起始地址,还要知道存储该数据的长度,而不同类型的数据编码方式也是不一样的。
  2. 为了解决上述问题,引入了数据类型的概念。也就是说,可以把所有的数据归纳为有限的几种类型,而同一种类型的数据具有相同的长度,占用相同大小的内存空间,具有相同的编码方式。这样当访问某一个数据时,首先根据它的内存地址找到相应的存储位置,然后根据它的类型来确定它的长度和编码方式,就能正确、完整地访问这个数据。

Java 语言的数据类型分为基本数据类型和引用数据类型。

基本数据类型

Java 有八种基本数据类型,其中有六种数字类型,一种字符类型,一种布尔类型。数字类型可分为整数类型和浮点类型。

类型名称 关键字 默认值 占用内存 取值范围
字节型 byte 0 1 字节 8位 -128~127
短整型 short 0 2 字节 -32768~32767
整型 int 0 4 字节 32位 -2147483648~2147483647 -231 ~ 231-1
长整型 long 0L 8 字节 -9223372036854775808L~9223372036854775807L
单精度浮点型 float 0.0f 4 字节 +/-3.4E+38F(6~7 个有效位)
双精度浮点型 double 0.0 8 字节 +/-1.8E+308 (15 个有效位)
字符类型 char ‘u0000’ 2 字节 ISO 单一字符集
布尔类型 boolean false 1 字节 true 或 false

整数类型

字节型(byte)

byte 数据类型是 8 位、有符号的,以二进制补码表示的整数;

字节类型是最小的整数类型, 当用户从网络或文件中处理数据流时,或者处理可能与 Java 的其他内置类型不直接兼容的未加工的二进制数据时,该类型非常有用。

短整型(short)

short 数据类型是 16 位、有符号的以二进制补码表示的整数 ;

short 类型限制数据的存储为先高字节,后低字节,这样在某些机器中会出错,因此该类型很少被使用。

整型(int)

int 数据类型是 32 位、有符号的以二进制补码表示的整数;

int 类型是最常使用的一种整数类型。

长整型(long)

long 数据类型是 64 位、有符号的以二进制补码表示的整数;

对于大型程序常会遇到很大的整数,当超出 int 类型所表示的范围时就要使用 long 类型。

浮点类型

单精度浮点型(float)

float 数据类型是单精度、32位、符合 IEEE 754 标准的浮点数;

Java 默认的浮点型是 double,所以想声明一个数据为 float 类型时,需要在数值后追加字母 f 或 F。

双精度浮点型(double)

double 数据类型是双精度、64 位、符合 IEEE 754 标准的浮点数;

Java 默认的浮点类型,当单纯的声明了一个小数类型的数值时,该数值为 double 类型。

字符类型(char)

char 类型是一个单一的 16 位 Unicode 字符;

Java 语言中的字符类型(char)使用两个字节的 Unicode 编码表示,它支持世界上所有语言,可以使用单引号字符或者整数对 char 型赋值(相当于一个整型值,ASCII 码值)。

一般计算机语言使用 ASCII 编码,用一个字节表示一个字符。ASCII 码是 Unicode 码的一个子集,用 Unicode 表示 ASCII 码时,其高字节为 0,它是其前 255 个字符。

Unicode 字符通常用十六进制表示。例如“\u0000”~“\u00ff”表示 ASCII 码集。“\u”表示转义字符,它用来表示其后 4 个十六进制数字是 Unicode 码。

布尔类型(boolean)

boolean 数据类型表示一位的信息(一位即 1/8 字节,实际处理按 1 字节处理);

布尔类型(boolean)用于对两个数值通过逻辑运算,判断结果是“真”还是“假”。Java 中用保留字 true 和 false 来代表逻辑运算中的“真”和“假”。因此,一个 boolean 类型的变量或表达式只能是取 true 和 false 这两个值中的一个。

在 Java 语言中,布尔类型的值不能转换成任何数据类型,true 常量不等于 1,而 false 常量也不等于 0。这两个值只能赋给声明为 boolean 类型的变量,或者用于布尔运算表达式中。

基本数据类型转换

自动类型转换

不同类型的数据在进行运算时,小类型会自动向大类型做类型转换,然后再进行运算

小—->大 byte -> short -> int -> long -> float -> double

double d = 20;

强制类型转换

强制转换的数据类型必须是兼容的。
大—->小 小类型 变量名 = (小类型) 值

int i = (int) 20f;

注意:自增/自减运算符、复合赋值运算符底层做了优化,内部自动强制类型转换;(下方面试题)
如:++, —, +=, -=, ……

面试题:下面两个表达式对吗?

short s1 = 1; s1 = s1 + 1;

short s1 = 1; s1 += 1;
  1. 错误!根据java的基本数据类型转换规则,s1 为 short 类型的变量,在表达式 s1 = s1 + 1; 中,s1 会自动转为 int 类型与 1 进行运算,运算结果为 int 类型,而 int 类型的值赋值给 short 类型的变量时需要强制类型转换。

  2. 正确!在复合赋值运算符底层自动进行强制类型转换,所以此处实际上是 s1 = (int)(s1 + 1);

类型提升

是指在多种不同数据类型的表达式中,类型会自动向范围表达大的值的数据类型提升;

long count = 1000000;
int price = 1999;
long totalPrice = price * count;

引用类型

在 Java 中,除了基本数据类型的数据类型称之为 引用类型。

  • 在 Java 中,引用类型的变量非常类似于 C/C++ 的指针。引用类型指向一个对象,指向对象的变量是引用变量。这些变量在声明时被指定为一个特定的类型,比如 Employee、Puppy 等。变量一旦声明后,类型就不能被改变了。
  • 对象、数组都是引用数据类型。
  • 所有引用类型的默认值都是 null。
  • 一个引用变量可以用来引用任何与之兼容的类型。

引用类型的类型转换与基本数据类型类似,小类型可以自动向大类型转换,大范围类型对象则需要强制类型转换为小范围类型;

Java 参数的值传递:对于基本数据类型,参数存储的就是变量的值;对于引用数据类型,引用存储的是对象的内存地址。所以引用类型变量传入方法参数中,只要不改变对象的地址,就可以在方法外获取方法内设置的对象属性。

包装类型

Java 的包装类型是基本数据类型对应的引用类型,贯彻了 Java 面向对象的思想。

类型名称 关键字 对应包装类型 占用内存 默认值
字节型 byte Byte 1 字节 null
短整型 short Short 2 字节 null
整型 int Integer 4 字节 null
长整型 long Long 8 字节 null
单精度浮点型 float Float 4 字节 null
双精度浮点型 double Double 8 字节 null
字符类型 char Character 2 字节 null
布尔类型 boolean Boolean - null

自动装箱和拆箱

自动装箱和拆箱是 JDK 1.5 开始提供的特性。

  • 装箱:将基本类型用它们对应的引用类型包装起来;
  • 拆箱:将包装类型转换为基本数据类型; ```java // 自动装箱 valueOf(int) Integer i = 10;

// 自动拆箱 intValue() int n = i;

从反编译得到的字节码内容可以看出,在装箱的时候自动调用的是 Integer 的 valueOf(int) 方法。而在拆箱的时候自动调用的是 Integer 的 intValue() 方法。其他包装类型类似。

特殊的 Integer 缓存:在通过 valueOf 方法创建 Integer 对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache 中已经存在的对象的引用;否则创建一个新的 Integer 对象。
```java
public static Integer valueOf(int i) {
    if(i >= -128 && i <= IntegerCache.high)
        return IntegerCache.cache[i + 128];
    else
        return new Integer(i);
}

特殊的 Boolean 静态成员变量:在通过 valueOf 方法创建 Boolean 对象的时候,会返回 Boolean 类中提前创建好的 Boolean 类型的真假成员变量。

public static Boolean valueOf(boolean b) {
    return (b ? TRUE : FALSE);
}

public static final Boolean TRUE = new Boolean(true);

/** 
 * The <code>Boolean</code> object corresponding to the primitive 
 * value <code>false</code>. 
 */
pc static final Boolean FALSE = new Boolean(false);

更多内容:深⼊剖析 Java 中的装箱和拆箱