一、变量介绍
变量就是申请内存来存储值。也就是说,当创建变量的时候,需要在内存中申请空间。内存管理系统根据变量的类型为变量分配存储空间,分配的空间只能用来储存该类型数据。
1、变量声明和初始化
变量的声明:
int a;
int 是类型,a 是变量名或者说标识符。
变量初始化:
a = 10;
将 10 赋值给或者说初始化给变量 a。
也可以声明和初始化同时进行:
int a = 10;
2、变量内容的输出
再声明和初始化变量之后,我们还可以使用以下方式输出变量的内容:
public class Hello {
public static void main(String[] args) {
int age = 18;
//创建一个int变量然后初始化
float height = 1.8f;
//创建一个float变量然后初始化
System.out.println(age);
System.out.println(height);
}
}
运行结果:
3、变量的内存大小
变量在初始化时的类型不同,系统对其分配的内存大小是不同的。例如 int 类型是 4 字节,double 是8字节。
在同一个作用域中不能有重名的变量。
二、数据类型
Java 的数据类型分为基本数据类型和引用数据类型:
下面将会对基本数据类型进行详细介绍。Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。
1、type
特点 | 详情 |
---|---|
类型名称 | byte |
位数 | 8位 |
符号性 | 有符号 |
存储形式 | 二进制补码 |
最小值 | -128 (-2^7) |
最大值 | 127 (2^7-1) |
默认值 | 0 |
从它的名字上面也可以看出来,它的大小是一个字节,对于比较小的整数可以用它来存储,以节省空间。
byte a = 10;
byte b = -20;
2、short
特点 | 详情 |
---|---|
类型名称 | short |
位数 | 16位 |
符号性 | 有符号 |
存储形式 | 二进制补码 |
最小值 | -32768 (-2^15) |
最大值 | 32767 (2^15-1) |
默认值 | 0 |
short 又叫短整型,占用 2 字节,在数值较小时可以使用它来存储,以节省空间。
short a = 1000;
short b = -2000;
3、int
特点 | 详情 |
---|---|
类型名称 | int |
位数 | 32位 |
符号性 | 有符号 |
表示形式 | 二进制补码 |
最小值 | -2,147,483,648 (-2^31) |
最大值 | 2,147,483,647 (2^31-1) |
默认值 | 0 |
int 就是默认整型类型,占用 4 字节。
int a = 60000;
int b = -70000;
4、long
特点 | 详情 |
---|---|
类型名称 | long |
位数 | 64位 |
符号性 | 有符号 |
表示形式 | 二进制补码 |
最小值 | -9,223,372,036,854,775,808 (-2^63) |
最大值 | 9,223,372,036,854,775,807 (2^63-1) |
默认值 | 0L |
long 又叫长整型,对于比较大的数据可以用它来存储,占用 8 字节。由于整形常量默认是 int 类型的,如果要初始化 long 类型的数据,要在整形常量后加上 L 以表示它是长整型,这里的 L 大写小写都行,但是一般大写 L 防止与数字 1 混淆。
long a = 10000000000L;
long b = -20000000000L;
5、float
特点 | 详情 |
---|---|
类型名称 | float |
位数 | 32位 |
符号性 | 有符号 |
表示形式 | IEEE 754 |
默认值 | 0.0f |
float 又叫单精度浮点数,用于精度比较小的情况。由于浮点数常量的默认类型是 double 类型, 所以在初始化时要在常量后加上 f 。
float a = 2.34f;
float b = -3.14f;
6、double
特点 | 详情 |
---|---|
类型名称 | double |
位数 | 64位 |
符号性 | 有符号 |
表示形式 | IEEE 754 |
默认值 | 0.0d |
double 又叫双精度浮点数,精度比 float 高,但实际上有些情况还是不能胜任。同时可以在常量值后加上 D 以表示这个数据是 double 类型,但是对于常量浮点数默认就是 double 类型的,所以加不加 D 作为后缀都可以。
double a = 3.1415926;
double b = -2.3453534D;
7、char
特点:
特点 | 详情 |
---|---|
类型名称 | char |
位数 | 16位 |
符号性 | 无符号 |
存储形式 | Unicode 字符 |
最小值 | \u0000 (0) |
最大值 | \uffff (65535) |
默认值 | \u0000 |
用途 | 存储单个字符 |
介绍:
我们可以将一个字符存储到 char 类型的变量中(单个字符赋值使用单引号):
char ch = 'A';
对于 char 类型的数据,实际上存储的是字符对应的 Unicode 码。所以我们可以在初始化时直接赋值给 char 类型变量一个整数:
public class Test {
public static void main(String[] args) {
char ch = 65;
System.out.println(ch);
}
}
这样会打印这个整数对应的 Unicode 字符:
当然我们也可以将这个字符类型强制转换为整型(因为 char 类型的本质就是整型),然后以整型形式打印,就可以得到字符对应的 Unicode 码了:
public class Test {
public static void main(String[] args) {
char ch = '好';
System.out.println((int)ch);
}
}
这样就可以得到字符对应的 Unicode 码值了:
经过查询,我们发现,字符 '好' 对应的 Unicode 码值就是:
这与我们的运行结果是对应的。
与 C 语言的 char 比较:
对于 char 类型,Java 里的字符类型与 C 语言的不同,C 语言的 char 类型只有一个字节,而且只能存储 ASCII 字符集,不能存储 Unicode 字符的超出 ASCII 的部分。所以对于以下操作 C 语言的 char 类型是做不到的:
public class Test {
public static void main(String[] args) {
char ch = '好';
System.out.println(ch);
}
}
运行结果:
Java 的 char
类型是一个单一的 16 位 Unicode 字符,使用 UTF-16 编码。(对于这里有一个需要声明的点,Unicode 是一个字符集,而UTF-16是它的一个实现。其他的实现还有UTF-8和UTF-32)它的取值范围是从 \u0000
到 \uffff
(即从 0 到 65535),这允许它能够表示世界上绝大多数字符的标准集(包括 ASCII、拉丁字母、汉字等)。因此,在 Java 中,我们可以使用 char
类型来存储像 '好' 这样的 Unicode 字符。
另一方面,C 语言的标准 char
类型通常是 8 位的,并且主要用来表示 ASCII 字符集,它的取值范围是从 0 到 255 或 -128 到 127(取决于编译器是否将 char 视为有符号类型)。由于它的大小限制,C 语言的标准 char
类型不能直接表示 Unicode 字符集中的超出 ASCII 字符集的字符。如果在 C 中想要处理 Unicode 字符,通常会使用其他数据类型,如 wchar_t
,这是一个宽字符类型,其大小和编码方式可以变化,依赖于平台和编译器设置,可能是 16 位或 32 位。
char 类型的存储:
当我们在使用以下语句对一个字符型变量进行初始化时,这个字符常量值是怎么存储的呢:
char ch = 'a';
对于字符型变量,内存中存储的其实是它对应的 Unicode 码值的二进制。
编码方式:
-
ASCII(American Standard Code for Information Interchange,美国信息交换标准代码):ASCII 是最早的字符编码标准之一,使用一个字节(8位)来表示一个字符。原始的 ASCII 编码只使用了 7 位,共计 128 个字符。它包含了英文字母(大小写)、数字、标点符号和一些控制字符。扩展 ASCII 码:后来的很多国家扩展 ASCII 则使用了全部 8 位,增加了更多字符,这些国家扩展的 ASCII 码的前128个字符是一样的,但是后面的 128~255 的编码各不相同(因为每个国家的字母不一定一样,所以后面的编码实现不同),导致使用不同的编码实现方式打开不同的文件会导致乱码。
-
UTF-8(Unicode Transformation Format - 8-bit):UTF-8 是一种变长编码,是一种 Unicode 字符集的编码方式实现,可以在表示 Unicode 字符时使用 1 到 4 个字节。UTF-8 兼容 ASCII 编码,即 ASCII 字符使用一个字节表示,而非 ASCII 字符需要多个字节(例如汉字使用3字节)。UTF-8 是互联网上最常用的字符编码方式,因为它兼容 ASCII,并可以表示世界上几乎所有的字符。
-
GBK:GBK 是对 GB2312 编码的扩展,主要用于表示中文字符。GBK 使用两个字节表示一个字符,其中包含了 GB2312 中的字符及更多的汉字和符号。GBK 兼容 GB2312,所以 GB2312 中的字符可以直接在 GBK 中使用。
-
GB2312:GB2312 是中国国家标准,主要用于表示简体中文字符。它使用两个字节表示一个字符,其中包含了大部分常用的汉字和一些符号。GB2312 的字符集较为有限,不包含繁体中文和其他语言字符。
-
Big5 码:Big5 码主要用于表示繁体中文字符。它使用两个字节表示一个字符,其中包含了繁体中文字符及一些符号。Big5 码与 GB2312 和 GBK 不兼容,因为它们使用了不同的字符集。
8、boolean
特点 | 详情 |
---|---|
类型名称 | boolean |
位数 | 不明确,依赖于具体实现 |
符号性 | 无 |
表示形式 | true 或 false |
默认值 | false |
boolean 又叫布尔类型,一般用于逻辑判断。
boolean isRight = true;
补充
数据类型的内存大小:
由于 Java 的代码是在 JVM 中运行的,所以对于不同的平台这些数据类型的内存大小都是一样的。这一点与 C 语言不同。这种固定大小的设计确保了 Java 程序在不同平台上的一致性。相比之下,C 语言的基本数据类型大小是依赖于编译器和目标平台的。例如,int
在某些系统上可能是 16 位,而在其他系统上可能是 32 位。这种灵活性使得 C 语言非常接近底层,可以针对特定硬件进行优化,但同时也要求程序员在编写跨平台代码时更加小心,以确保代码在不同环境下的正确性。
数据不兼容:
当我们使用不兼容的数据来赋值时:
public class Test {
public static void main(String[] args) {
int a = 100L;
}
}
会出现以下报错:
这里应当使用 100L 对应的数据类型,也就是 long 类型。
Java 中整型变量一般声明为 int 类型,除非是 int 无法表示的大数才使用 long 。
当我们使用不同精度的浮点数进行赋值时:
public class Test {
public static void main(String[] args) {
float a = 1.0;
}
}
我们知道浮点数常量的默认类型是 double ,当我们将浮点数不加 f 后缀赋值给 float 类型,就相当于将 double 类型数据赋值给 float 类型的变量,这样就会导致精度损失,所以会出现以下报错:
浮点数赋值补充:
再对于浮点数赋值时,如果我们要赋值的值整数位为零,可以不加整数位,直接一个小数点后接小数位,就像这样:
public class Test {
public static void main(String[] args) {
double num = .123;
//这里赋值给num的值为0.123
System.out.println(num);
}
}
运行结果:
我们还可以使用科学计数法形式的数据对浮点数变量进行赋值:
public class Test {
public static void main(String[] args) {
double num1 = 1.023e2;
//这里赋值给num1的值为102.3
double num2 = 2.333E-2;
//这里赋值给num2的值为0.02333
System.out.println("num1 = " + num1);
System.out.println("num2 = " + num2);
}
}
运行结果:
1.023e2 就相当于 1.023 * 10 ^ 2 。这里的 e 是 exponent 的缩写,是幂的意思,这里的 e 大写小写都可以,指数可以是正负整数。
浮点数精度:
对于一个浮点数一般使用 double 类型存储,因为 double 的精度较高。可以通过下面这个例子看出来:
public class Test {
public static void main(String[] args) {
double num1 = 2.123456789;
//双精度浮点数一般能保留到小数点后15~16位
float num2 = 2.123456789f;
//单精度浮点数一般能保留到小数点后6~7位
System.out.println("双精度 num1 = " + num1);
System.out.println("单精度 num2 = " + num2);
}
}
运行结果:
双精度浮点数一般能保留到小数点后15~16位,单精度浮点数一般能保留到小数点后6~7位。
一个小细节:
public class Test {
public static void main(String[] args) {
double num1 = 1.1;
double num2 = 3.3 / 3;
System.out.println("1.1 num1 = " + num1);
System.out.println("3.3 / 3 num2 = " + num2);
}
}
虽然这里的 3.3 / 3 我们都知道是 1.1 ,但是这里输出的却不是 1.1 ,而是一个极其接近 1.1 的数。
浮点数在计算机中通常使用 IEEE 754 标准来表示,这种表示方法在存储时不能精确表示所有小数。特别是那些在十进制中有限的小数,在二进制浮点表示中可能是无限的。实际上这里的 3.3 转换为二进制的可能是无限循环小数,由于 double 精度是有限的,无法存储无限循环的小数,所以这里得到的结果是一个很接近 1.1 的小数,可以看到这里的 1.0999999999999999 小数位刚好是 16 位,确实是 double 类型精度的极限。
浮点数详细介绍补充说明:
Java 中的浮点数类型(float
和 double
)遵循 IEEE 754 标准,这与 C 语言中的浮点数类型(float
和 double
)相同。IEEE 754 是一个定义浮点数运算的国际标准,它规定了浮点数的表示、运算和舍入规则。
我之前的文章《C语言——数据存储_存储的c语言编程-CSDN博客》中有详细的介绍过的浮点数。
这里的介绍不仅适用于 C 语言,同样适用于 Java 。
三 、加号的使用
1. 数值加法
当 +
运算符应用于数值类型(byte、short、int、long、float、double)的操作数时,它执行加法运算。
整数加法:如果两个操作数都是整型(如 byte、short、int、long),结果也是整型。如果操作数类型不同,它们会按照从小到大的顺序(byte -> short -> int -> long)进行类型提升,运算结果的类型是提升后的类型。
int a = 5;
int b = 3;
int sum = a + b; // 结果是 8
浮点数加法:如果至少有一个操作数是浮点型(float、double),则进行浮点数加法。整数和浮点数相加时,整数会被提升为浮点数类型,运算结果类型是最大的那个操作数的类型。
double a = 5.5;
int b = 3;
double sum = a + b; // 结果是 8.5
2. 字符串连接
当 +
运算符的操作数中至少有一个是字符串(String
类型)时,Java 会将 +
运算符作为字符串连接操作来执行。此时,它会将非字符串操作数转换为字符串,然后将这些字符串连接在一起。
字符串与字符串连接:
String hello = "Hello, ";
String world = "world!";
String greeting = hello + world; // 结果是 "Hello, world!"
字符串与其他类型数据连接:如果其中一个操作数是字符串,另一个是非字符串(如数值、布尔值等),非字符串操作数将转换成字符串,然后进行连接。
String base = "Base score: ";
int score = 100;
String result1 = base + score; // 结果是 "Base score: 100"
String result2 = score + base; // 结果是 "100Base score: "
这种转换不仅适用于基本数据类型,也适用于对象。对于对象,Java 会调用对象的 toString()
方法来获取其字符串表示,然后进行连接。
特殊案例
在一系列加法操作中,如果涉及到字符串连接和数值加法,操作是从左到右依次进行的。因此,如果先遇到字符串,后续的操作数都会被转换为字符串进行连接。如果先进行数值加法,只有在遇到字符串后才开始进行字符串连接。
String result1 = "Sum: " + 5 + 7; // 结果是 "Sum: 57"
String result2 = 5 + 7 + " = Sum"; // 结果是 "12 = Sum"
示例:
public class Test {
public static void main(String[] args) {
System.out.println(21 + 34 + "nihao" + 1 + 2 + 3 + 4);
}
}
运行结果:
可以发现与上面的描述是对应的。
也就是说这里的多个 + 运算,运算顺序是从左到右的,首先是 21 + 34 ,得到 55 ,然后 55 + "nihao" 得到 "55nihao" ,然后 "55nihao" + 1 得到 "55nihao1" ,然后 "55nihao1" + 2 得到 "55nihao12" ,然后 "55nihao12" + 3 得到 "55nihao123" ,然后 "55nihao123" + 4 得到 "55nihao1234" ,所以最终打印的是这样的一个字符串。