Java 04 – Java的数据类型及数据类型之间的转换
目录
1 数据类型
1.1 计算机的存储单元
变量是内存中的小容器, 用来存储数据.
(1) 计算机内存是怎么存储数据?
无论是内存还是硬盘, 计算机存储设备的最小信息单元叫
位(bit)
, 又叫作“比特位”, 通常用小写字母b表示.而计算机的最小的存储单元叫
字节(Byte)
, 通常用大写字母B表示, 字节由连续的8个比特位组成, 即1Byte=8bit.
(2) 常用的存储单位:
$2^{10}$ = 1024 —— 这是计算机中的“整数”. 其他存储单位之间的换算方式如下:
1B(字节) = 8bit | 1KB = 1024B |
---|---|
1MB = 1024KB | 1GB = 1024MB |
1TB = 1024GB | 1PB = 1024TB |
1.2 为什么要有数据类型?
Java语言是强类型语言, 对每一种数据都定义了明确的具体数据类型;
不同数据类型的变量/常量在内存中将占用不同大小的内存空间.
—— 这样一来就能更有效地利用内存.
1.3 Java语言中的数据类型
Java语言中的数据类型分为: ① 基本数据类型, ② 引用数据类型.
(1) 基本数据类型:
四类 | 八种 | Byte数 | 能表示的数据范围 | 默认值 |
整型 | byte | 1 | -128 ~ 127 | 0 |
short | 2 | -32,768 ~ 32,767 | 0 | |
int | 4 | -2,147,483,648 ~ 2,147,483,647 | 0 | |
long | 8 | -2^(63) ~ 2^(63) – 1 | 0 | |
浮点型 | float | 4 | -3.403E38 ~ 3.403E38 | +0 |
double | 8 | -1.798E308 ~ 1.798E308 | +0 | |
字符型 | char | 2 | 0 ~ 65535 | null code point (‘\u0000’) |
布尔型 | boolean | 1 | 只有2个值: true 与 false | false |
注意: Java中整数默认是
int
, 小数默认是double
.
1.4 Java虚拟机中的数据类型
在Java虚拟机中的数据类型只分为两类: 原始类型和引用类型.
1.4.1 原始类型(primitive type)
原始类型对应的数值称为原始值, 有如下3类:
① 数值类型, 包括byte、short、int、long、char、float、double
.
② boolean类型, 只有true
和false
两个值, 默认是false
—— 虽然在JVM中定义了boolean
类型, 但是却没有指令直接支持其操作, 所以 对boolean
类型的操作都需要在编译后用虚拟机中的int
类型来表示 —— 1表示true, 0表示false.
③ returnAddress类型: 这种类型用在JVM中, 表示指向某个操作码opcode
的指针, 此操作码与虚拟机指令相对应. 与原始类型不同, returnAddress类型不对应任何Java类型, 并且不能被运行中的程序修改.
1.4.2 引用类型(reference type)
引用类型的数值称为引用值, 包括:
① 类类型(class type), 指向动态创建的类实例.
② 数组类型(array type), 指向动态创建的数组实例.
③ 接口类型(interface type), 指向实现了某个接口的类/数组实例.
引用类型和Java中对象的引用有关, 在虚拟机中, 对象表示为某个类的实例或者某个数组, 指向此对象的引用就用引用类型(reference)来表示.
关于引用类型的值, 可以比作指向对象的指针, 每个对象可能存在多个指向它的引用reference, 对象的操作、传递和检查都通过引用它的reference类型数据来进行.
在引用类型中还有一个特殊的值
null
, 当一个引用不指向任何对象时, 它就用null
表示.null
作为引用类型的初始默认值可以转型成任意的引用类型.
1.5 扩展: 关于负数与进制
(1) 负数的二进制表现形式: 对应正数的二进制取反加1(二进制位都为1, 对应十进制的-1).
(2) 8进制以数字0
开头表示, 16进制以0x
开头表示.
2 数据类型转换
2.1 隐式数据类型转换
所谓隐式转换, 就是Java虚拟机内部自动实现, 对程序开发人员来说, 这个转换是透明的. 具体是指:
取值范围小的数据类型与取值范围大的数据类型进行运算, 会先将小的数据类型提升为大的,再运算.
—— 隐式数据类型转换又被叫作自动类型提升.
2.1.1 隐式转换规则
基本数据类型之间会发生隐式类型转换的情形:
(byte, short, char) -> int -> long -> float -> double
说明:
①
byte、short、char
类型的值都会被提升为int
类型, 再去计算;② 只要有一个操作数是
long
类型, 计算结果就是long
类型;③ 只要有一个操作数是
float
类型, 计算结果就是float
类型;④ 只要有一个操作数是
double
类型, 计算结果就是double
类型.
2.1.2 char转换为int的示例
System.out.println('a'); // 结果是 a
System.out.println('a' + 1); // 结果是 98
说明: 'a' + 1
操作存在隐式数据类型转换 —— 由于字符'a'
在ASCII码中对应的 int 值是97, 所以在执行'a' + 1
操作后, 结果就是98.
2.1.3 其他示例代码
/**
* "+" 是一个运算符, 做加法运算的. 运算时, 一般要求参与运算的数据的类型要保持一致
* @author Heal Chow
*/
public class TypeCastDemo {
public static void main(String[] args) {
// 直接输出运算的结果
System.out.println(3 + 4); //7
// 定义两个int类型的变量
int a = 3;
int b = 4;
int c = a + b;
System.out.println(c); // 7
// 定义一个byte类型, 定义一个int类型
byte bb = 2;
int cc = 5;
System.out.println(bb + cc); // 7
// 能不能不直接输出, 而是用一个变量接收呢?
// 用变量接收, 这个变量应该有类型
// byte dd = bb + cc; // 可能损失精度: int型数据范围比byte型的大, byte表示不完整
int dd = bb + cc; // 不会损失精度
System.out.println(dd);
}
}
2.2 强制数据类型转换
2.2.1 强制转换的格式
目标类型 变量名 = (目标类型)(被转换的数据);
例如: int num = (int) 5.0;
就是把 float 类型的数值5转换为 int 类型.
2.2.2 强制转换注意事项
如果强制转换时, 被转换的数据超出了转换后数据类型的取值范围, 得到的结果会与期望的结果不同.
—— 也就是数据在表示精度上出现了损失, 所以不建议强制转换.
2.2.3 示例代码
/**
* 强制类型转换的示例
* @author Heal Chow
*/
public class ForceTypeCast {
public static void main(String[] args) {
int a = 3;
// byte占1个8位, 而机器中所有的整数都是默认以int型存储的4个8位),
// 编译器检查到3在byte可表示的范围内, 就回自动降低精确度
byte b = 4;
// 这里b会自动类型提升
int c = a + b;
// b + a是变量, 由于操作后的结果可能大于127(byte类型变量可表示的范围上限),
// 就不会自动类型提升, 表现为编译不通过
// b = b + a;
// 强制类型转换, 易出错
byte d = (byte) (a + b);
// char的值在0-65535之间, 查表知97为'a'
char ch1 = 97;
char ch2 = 'a';
// "" + X表示将X拼接到""字符串之后, 变为一个更长的字符串
System.out.println("ch1=" + ch); // 结果是 ch1=a
System.out.println("ch2=" + (ch2 + 1)); // 结果是 ch2=98
System.out.println("ch2=" + (char)(ch2 + 1)); // 结果是 ch2=b
}
}
2.3 扩展: 能把int值转换成byte吗
答案如下:
在Java虚拟机指令集的设计中, 由于操作码的长度为1字节, 这导致了指令的总数必须控制在256个以内.
而Java有8大基本数据类型 (byte,short,int,long,float,double,char,boolean), 如果给每种类型都设计一套指令, 那么就会产生8套重复冗余的指令, 指令总数肯定会超过256个.
为了避免这个问题, Java虚拟机指令集在设计时刻意避开了一些数据类型:
大部分的指令都没有直接支持byte、char、short、boolean
类型的数据, 编译器会在编译期或运行期:
① 将
byte
和short
类型的数据 通过类型转换指令 带符号拓展 为相应的int
类型的数据;② 将
boolean
和char
类型的数据 通过类型转换指令 零位拓展 为相应的int
类型的数据.
因此, 大多对 Java 中boolean、byte、short、char
类型数据的操作, 实际上都是使用 JVM 中int
类型作为运算类型来操作的.
也就是说, byte、short、char、boolean
类型的数据在压入栈, 或者从Java堆中获取这些类型的数据的时候, 它们就已经被转化成了int
类型.
说明: 示例代码可在 我的GitHub上 查看并下载.
参考资料
(全文完)
(感谢阅读, 转载请注明作者和出处 瘦风的南墙 , 请勿用于任何商业用途)