基本类型
导航 语言基础 主题: ) |
原始数据类型是 Java 语言中最基本的数据类型。共有 8 种:boolean
、byte
、char
、short
、int
、long
、float
和 double
。这些类型是 Java 中数据操作的基础。这些类型只有一种用途——存储一种纯净、简单的值。因为这些数据类型默认在 Java 类型系统中定义,所以它们附带了一些预定义的操作。您不能为这些原始类型定义新的操作。在 Java 类型系统中,还有三类原始类型
- 数值类型:
short
、int
、long
、float
和double
。这些原始数据类型只保存数值数据。与这些数据类型相关的操作是 基本算术(加、减等)或 比较(大于、等于等) - 文本类型:
byte
和char
。这些原始数据类型保存字符(可以是 Unicode 字母或数字)。与这些类型相关的操作是文本操作(比较两个词、连接字符组成词等)。但是,byte
和char
也可以支持算术运算。 - 布尔和空类型:
boolean
和null
。
所有原始类型都有固定的大小。因此,原始类型的取值范围是有限的。较小的原始类型(byte
)可以包含的值比较大的类型(long
)少。
类别 | 类型 | 大小(位) | 最小值 | 最大值 | 精度 | 示例 |
---|---|---|---|---|---|---|
整数 | byte
|
8 | -128 | 127 | 从 +127 到 -128 | byte b = 65;
|
char
|
16 | 0 | 216-1 | 所有 Unicode 字符[1] | char c = 'A';
| |
short
|
16 | -215 | 215-1 | 从 +32,767 到 -32,768 | short s = 65;
| |
int
|
32 | -231 | 231-1 | 从 +2,147,483,647 到 -2,147,483,648 | int i = 65;
| |
long
|
64 | -263 | 263-1 | 从 +9,223,372,036,854,775,807 到 -9,223,372,036,854,775,808 | long l = 65L;
| |
浮点型 | float
|
32 | 2-149 | (2-2-23)·2127 | 从 3.402,823,5 E+38 到 1.4 E-45 | float f = 65f;
|
double
|
64 | 2-1074 | (2-2-52)·21023 | 从 1.797,693,134,862,315,7 E+308 到 4.9 E-324 | double d = 65.55;
| |
其他 | boolean
|
-- | -- | -- | false, true | boolean b = true;
|
void
|
-- | -- | -- | -- | -- |
整数类型会默默地溢出
|
|
由于 Java 是强类型语言,因此您不能将浮点数(带小数点的数字)分配给整数变量
代码段 3.53:将浮点数设置为 int (整数)类型的值。
int age;
age = 10.5;
|
原始类型应通过适当的值设置。原始类型可以使用字面量初始化。大多数字面量是原始类型的值,除了 字符串字面量,它是 String
类的实例。
计算机科学中的数字
[edit | edit source]编程可能不再像以前那样仅仅是处理大量的数字,那样既琐碎又枯燥。然而,如今用任何编程语言(更不用说 Java)编写的代码中,大部分代码都在痴迷地处理数字,无论是生成巨大的质数,[2] 还是仅仅计算你踏板车的排放成本。1965 年,双子座 5 号 太空任务险些因为一个编程错误而遭遇致命事故。[3] 1979 年,一个计算机程序高估了 5 个核反应堆抵御地震的能力,这些反应堆暂时关闭。[4] 这两个编程错误有一个共同点:错误发生时,所计算的数据是数值数据。Java 从以往的经验中吸取教训,为数值数据添加了改进的类型检查,并重点强调正确识别不同类型的数值数据。在编程时,您必须认识到数值数据的重要性。
数字使用二进制系统存储在内存中。内存就像一个网格状的单元格
每个单元格可以包含一个二进制数(简称为位),也就是说,是零或一
0 |
1 |
1 |
0 |
0 |
1 |
0 |
1 |
实际上,每个单元格都包含一个二进制位,因为一位大致相当于1
,而内存中的空单元格表示0
。单个二进制位只能保存两种可能的值:零或一。
内存状态 | 给出 | ||||||||
0 |
→ | 0 | |||||||
1 |
→ | 1 |
多个位组合在一起可以保存多个排列——2 位可以保存 4 个可能的值,3 位可以保存 8 个可能的值,依此类推。例如,8 位可以保存的最大数字(二进制为11111111
)在十进制系统中为255
。因此,数字 0 到 255 可以放在 8 位中。
内存状态 | 给出 | ||||||||
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
→ | 0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
→ | 1 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
→ | 2 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
→ | 3 |
... |
... | ||||||||
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
→ | 255 |
一切都很好,但是通过这种方式,我们只能保存正数(或无符号整数)。它们被称为无符号整数。无符号整数是所有为正的整数值,不包含负值。出于这个原因,我们将要求 8 位中的一个位保存有关数字符号(正或负)的信息。这样我们就只剩下 7 位可以用来计数。这些 7 位可以保存的最大数字(1111111
)在十进制系统中为127
。
正数
内存状态 | 给出 | |||||||||
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
→ | 0 | |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
→ | 1 | |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
→ | 2 | |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
→ | 3 | |
... |
... |
... | ||||||||
0 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
→ | 127 |
负数
内存状态 | 给出 | |||||||||
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
→ | -128 | |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
→ | -127 | |
1 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
→ | -126 | |
1 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
→ | -125 | |
... |
... |
... | ||||||||
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
→ | -1 |
总而言之,使用这种方法,8 位可以保存从-128
到127
(包括零)的数字——总共 256 个数字。这应该不失为一种不错的权衡。无符号整数的相反是有符号整数,它可以保存正值和负值。
但是,较大的数字怎么办?您需要更多位来保存较大的数字。这就是 Java 数值类型发挥作用的地方。Java 有多种数值类型——它们的大小取决于参与运算的位数。
在 Java 中,使用专门用于保存数值数据的类型来处理数字。但是在深入研究这些类型之前,我们必须首先确立一些概念。就像你在高中(甚至小学)一样,Java 中的数字被分为不同的组和系统。正如你现在所知道的,数字系统包括整数(0、1、2 ... ∞);负整数(0、-1、-2 ... -∞)甚至实数和有理数(圆周率值、¾、0.333~ 等)。Java 简单地倾向于将这些数字分为两个不同的组,整数(-∞ ... 0 ... ∞)和浮点数(任何带小数点或分数表示的数字)。目前,我们只关注整数值,因为它们更容易理解和操作。
通过我们目前所学,我们将识别在 Java 中可创建和操作的不同类型的有符号整数值。以下是最基本数值类型的表格:整数。正如我们之前讨论过的,Java 中用于整数的数据类型同时适用于正数和负数,因此它们是有符号数值类型。数值类型的大小以位为单位,它决定了最小值和最大值。如有疑问,可以随时计算这些值。
让我们看看这些关于 Java 中基本整数类型的新知识如何融入大局。假设您要对一年中的天数进行数值操作——所有 365 天。您会使用什么类型?由于byte
数据类型仅能达到 127,您会冒将它赋值大于其允许最大值的风险吗?这样的决定可能会避免您从程序代码中出现的可怕错误。对这种数值操作来说,更明智的选择可能是short
。现在,为什么不能只创建一个数据类型来保存所有类型的数字?让我们来探讨一下原因。
当您告诉程序您需要使用一个整数时,比如即使是byte
,Java 程序也会在内存中分配一个空间。它会分配 8 位内存。虽然这对于当今拥有几乎上万亿这样的位空间的内存模块来说似乎无关紧要,但在其他情况下就很重要。一旦分配了内存,该部分内存就被使用了,只有在操作完成后才能回收。想象一个复杂的 Java 程序,您只使用long
整数作为数据类型。当没有空间进行更多内存分配任务时会发生什么?您是否听说过堆栈溢出错误。这就是发生的事情——您的内存很快就被完全用完了。所以,要谨慎选择数据类型。
说了这么多,让我们看看如何创建一个数值类型。数值类型以类型名称(short
、int
等)开头,然后为内存中分配的空间提供一个名称。以下是操作方法。假设我们需要创建一个变量来保存一年中的天数。
代码部分 3.54:一年中的天数。
short daysInYear = 365;
|
这里,daysInYear
是保存365
作为其值的变量的名称,而short
是该特定值的的数据类型。Java 中整数数据类型的其他用法可能会看到您编写类似以下代码的代码
代码部分 3.55:Java 中的整数数据类型。
byte maxByte = 127;
short maxShort = 32767;
int maxInt = 2147483647;
long maxLong = 9223372036854775807L;
|
可用于整数的数据类型是byte
、short
、int
和long
,但对于浮点数,我们使用float
或double
。现在我们知道了,我们可以修改代码部分 3.53中的代码,如下所示
代码部分 3.56:正确的浮点声明和赋值。
double age = 10.5;
|
为什么不是float
,您可能会问?如果我们使用float
,我们必须在数字后面添加f
作为后缀,所以10.5
应该写成10.5f
,如下所示
代码部分 3.57:定义float 类型浮点数的正确方法。
float age = 10.5f;
|
浮点数学运算永远不会抛出异常。非零值除以0
等于infinity
。非无限值除以infinity
等于0
。
问题 3.7:考虑以下代码
问题 3.7:原始类型赋值。
...
a = false;
b = 3.2;
c = 35;
d = -93485L;
e = 'q';
|
这是五个变量。有一个long
,一个byte
,一个char
,一个double
和一个boolean
。检索每个变量的类型。
答案 3.7:原始类型赋值和声明。
boolean a;
double b;
byte c;
long d;
char e;
a = false;
b = 3.2;
c = 35;
d = -93485L;
e = 'q';
|
a
只能是boolean
,因为只有 boolean 可以处理 boolean 值。e
只能是char
,因为只有 char 可以包含一个字符。b
只能是double
,因为只有 double 可以包含这里的十进制数。d
是long
,因为byte
不能包含这么小的值。c
是剩下的那个,所以它是byte
。
数据转换(强制转换)可以在两种原始类型之间发生。强制转换有两种类型
- 隐式:不需要强制转换操作;数值的大小总是保留的。但是,从整数转换为浮点类型时,精度可能会丢失
- 显式:需要强制转换操作;数值的大小可能不会保留
代码部分 3.58:隐式强制转换(int 转换为 long,强制转换不需要)。
int i = 65;
long l = i;
|
代码部分 3.59:显式强制转换(long 转换为 int,强制转换需要)。
long l = 656666L;
int i = (int) l;
|
下表显示了原始类型之间的转换,它显示了显式转换的强制转换操作
从byte |
从char |
从short |
从int |
从long |
从float |
从double |
从boolean | |
---|---|---|---|---|---|---|---|---|
到byte |
- | (byte) | (byte) | (byte) | (byte) | (byte) | (byte) | N/A |
到char |
- | (char) | (char) | (char) | (char) | (char) | N/A | |
到short |
(short) | - | (short) | (short) | (short) | (short) | N/A | |
到int |
- | (int) | (int) | (int) | N/A | |||
到long |
- | (long) | (long) | N/A | ||||
到float |
- | (float) | N/A | |||||
到double |
- | N/A | ||||||
到boolean |
N/A | N/A | N/A | N/A | N/A | N/A | N/A | - |
与 C、C++ 和类似语言不同,Java 无法将false
表示为0
或null
,也无法将true
表示为非零。Java 无法从 boolean 强制转换为非 boolean 原始数据类型,反之亦然。
对于非原始类型
到 Integer | 到 Float | 到 Double | 到 String | 到 Array | |
---|---|---|---|---|---|
整数 | - | (float)x | (double)x x.doubleValue() |
x.toString() Float.toString(x) |
new int[] {x} |
Float | java.text.DecimalFormat("#").format(x) | - | (double)x | x.toString() | new float[] {x} |
Double | java.text.DecimalFormat("#").format(x) | java.text.DecimalFormat("#").format(x) | - | x.toString() | new double[] {x} |
String | Integer.parseInt(x) | Float.parseFloat(x) | Double.parseDouble(x) | - | new String[] {x} |
Array | x[0] | x[0] | x[0] | Arrays.toString(x) | - |
- ↑ 根据"STR01-J. 不要假设 Java char 完全代表 Unicode 代码点". 卡内基梅隆大学 - 软件工程研究所. 检索于 2018 年 11 月 27 日.,并非所有 Unicode 字符都适合 16 位表示
- ↑ 截至编辑(2013 年 12 月 11 日),互联网梅森素数大搜索 项目迄今为止已将最大的素数识别为 17,425,170 位数。素数对密码学家很有价值,因为数字越大,他们可以使用该特定数字使他们的数据加密逻辑越安全。
- ↑ 由于软件错误,双子座 5 号在计划的太平洋着陆点以西 130 公里处着陆。地球的自转速度被编程为每太阳日旋转一次,而不是正确的值,每恒星日旋转一次。
- ↑ 他们设计中使用的一个程序使用了变量的算术和,而它应该使用它们的绝对值的和。(Evars Witt,“小电脑和大问题”,美联社新闻,1979 年 3 月 16 日。另见 Peter Neumann,“关于软件正确性和社会进程的社论”软件工程笔记,第 4 卷(2),1979 年 4 月,第 3 页)