原始类型

Java 是强类型语言,在编译时会检查所有变量、表达式的类型是否兼容。Java 为数据定义了 8 种原始类型(primitive type),分为 4 组:

  • 整型:byte、short、int、long,表示整数。
  • 浮点数:float、double,表示小数。
  • 字符:char,表示字符集中的元素。
  • Boolean:boolean,表示 true/false 值。

上述数据类型构成了自定义数据类型的基础。原始类型存在的原因之一是效率高。Java 的原始类型所占位数的大小固定,不像 C/C++ 取决于具体机器环境。

整型

4 种整型变量都是有符号数,Java 不支持无符号数。当 byte 或 short 类型参与表达式计算时,类型会提升为 int,然后再进行计算求值。

类型名 位宽 范围
byte 8 \(-2^{7}\) to \(2^{7}-1\)
short 16 \(-2^{15}\) to \(2^{15} - 1\)
int 32 \(-2^{31}\) to \(2^{31} - 1\)
long 64 \(-2^{63}\) to \(2^{63} - 1\)

浮点型

浮点数又称实数。Java 实现了标准的浮点类型和操作符集(IEEE-754)。

类型名 位宽 范围
double 64 \(4.9\times 10^{-324}\) to \(1.8 \times 10^{308}\)
float 32 \(1.4\times 10^{-45}\) to \(3.4\times10^{38}\)

字符

Java 使用 Unicode 码表示字符。Java 被创造的时候,Unicode 需要 16 位,所以 char 占 16 位。 char 可以参与部分运算,此时 char 代表字符还是 Unicode 码值,取决于上下文。char 可以使用自增运算符。

Boolean

boolean 类型的值是逻辑值,用于控制语句和循环语句。任何关系操作符产生的结果都是 boolean 类型。

字面值

整型字面值

默认的整数是 int 类型的十进制字面值(literals)。以 0 开头的字面值是八进制数,以 0x 或 0X 开头的字面值是十六进制数,以 0b 开头的字面值是二进制数。字面值中间可以使用下划线分隔,编译时自动去除,字面值的开始和结尾不允许使用下划线。下划线可以相连使用。字面值最后添加小写的 l(字母)或 L 表示是 long 类型。

浮点数字面值

默认的浮点数字面值是 double 类型。字面值后面添加 f 或 F 表示该字面值是 float 类型,添加 d 或 D 表示是 double 类型。可以使用科学计数法表示浮点数,此时底数使用 e 或 E 表示 10,如 1.0e-10 表示 \(1.0\times10^{-10}\)。使用 16 进制数表示时,使用 p 而不是 e 表示底数。如 0x12.2p2 表示 \((1\times16^{1}+2\times16^{0}+2\times16^{-1})\times 2^{2}=72.5\)。即 p 前面的数以 16 为基数,p 表示底数 2。下划线的用法和在整数中相同,也可用于小数部分。

Boolean 字面值

boolean 类型的字面值不能转换成其他类型,true 不等于 1,false 不等于 0。只能同类型赋值。

字符字面值

字符字面值可以将 Unicode 码值转成整数值进行运算。单引号括起来的单个字符为字符字面值。单引号内部以反斜线开头,紧跟着 3 位八进制数或者以'\u'开头,后面紧跟着 4 位十六进制数,都表示字符字面值。分别是八进制表示和十六进制表示。

字符串字面值

字符串字面值由双引号括起来的多个字符序列表示。每个字符都可以按照字符字面值的方式表示。Java 中字符串整体必须位于同一行,字符串内部不能直接换行。

变量

type identifier [= value,][, identifier...]

type 可以是原始类型、类的名称、接口的名称。identifier 是创建的变量名字。后面可以加上一个常量进行初始化。初始值的类型必须和变量声明的类型相同或者兼容。变量必须先声明再使用,否则编译不通过。

变量可以在声明的时候通过调用方法、使用其他变量或字面值进行初始化。

每当创建一个新块,同时也创建了一个新的作用域。在一个作用域内定义的变量在该作用域外不可见。变量的生命周期从该变量声明进入作用域开始,离开作用域为止。生命周期由作用域决定。虽然作用域可以嵌套,但是不能在内层作用域中声明和外层作用域中同名的变量。

类型转换

自动类型转换

当 1)两种类型兼容 2)目标类型可表示范围大于源类型 两个条件满足时,类型转换自动完成,此时称为 widening conversion。整数和浮点数符合这个规则,char 和 boolean 不兼容,同时数值类型也不会自动转换成这两种类型。

不兼容类型转换

当把一个可表示范围大的类型转换为可表示范围小的类型时,会有精度损失,因此不会发生自动类型转换,需要手动进行强制类型转换。int 转 byte 的方式是用待转的 int 值模 byte 可表示的最大值。当从浮点数转换到整数时,小数部分会截断,去除,整数部分取模。

targetType variable = (targetType)value

表达式中的自动类型提升

当 byte、short 和 char 类型在表达式中参与计算时,类型会自动转换成 int,中间结果是 int,最终结果会转换成(如需要)目标结果类型。

类型提升规则

计算时,表达式中的 byte、short 和 char 类型的值会提升为 int 类型。
如果参与运算的数类型为 long,则整个表达式类型提升为 long;
如果参与运算的数类型为 float,则整个表达式类型提升为 float;
如果参与运算的数类型为 double,则整个表达式类型提升为 double。

数组

一维数组

创建一维数组分两步:首先创建一个数组变量,然后使用 new 分配一块存储数组的内存,用数组变量引用该数组。

type varName[];
varName = new type[num];
// 下面一行等同于上面两行
type varName[] = new type[num];

定义数组时,如果没有赋初值,当数组类型为数值类型时,初始值默认为 0;为 boolean 类型时,默认为 false;为引用类型时,默认为 null。

type varName[] = {element1, element2,...};

给数组赋初值,但不指定数组大小时,会自动创建大小和初始元素个数相等的数组。
当使用不在有效索引范围内的索引访问数组时,会产生运行时错误。

多维数组

多维数组是数组的数组。

type varName[][] = new type[num][num];

由于多维数组是数组的数组,定义时可以仅指定第一维(最左边索引)的维数,剩下的维数可以之后指定,也可以指定不同大小的维度。

int a[][] = new int[2][];
a[0] = new int[1];
a[1] = new int[5];

多维数组初始化时,初始值可以是字面值、表达式。处于同一维的值使用大括号括起来。

int a[][] = {
 {...},
 {...}
};

另一种声明数组的语法

int[] a = new int[num];
int[][] a = new int[num][num];

与前面的声明方式等价。

局部变量类型推导

从 JDK10 开始,引入了一个新的上下文敏感(context-sensitive)的保留类型名(reserved type name)var。它用于局部变量类型推导。局部变量类型推导指声明具有初始值的局部变量时,可以用 var 代替变量的类型,变量的具体类型由编译器根据初始值的类型推导得出。局部变量类型推导的优点:消除了冗长的类型名和不可知的类型名(如匿名类)的书写。

// name 为 double 类型,等价于 double name = 1.0;
var name = 1.0;

当 var 不用于局部变量类型推导时,可以当作标识符。

// 合法,var 是 int 类型变量
int var = 1;

var 用于数组时,左边不需要方括号,添加方括号将出错。

var name = new int[10];

var 的一些限制

var 可以用于数组的声明,不能用于数组的初始化。

// 错误
var name = {1,2};

var 不能作为类名,也不能作为其他引用类型名,如接口、枚举、注解、泛型参数。

var 不能用于声明异常类型、lambda 表达式、方法引用。

参考

[1] Herbert Schildt, Java The Complete Reference 11th, 2019.

 posted on 2024-04-18 14:17  x-yun  阅读(9)  评论(0编辑  收藏  举报