第二章 变量和运算符
主要内容
- 关键字和标识符
- 变量和常量
- 八大基本数据类型
- Scanner键盘输入
- 基本数据类型的类型转换
- 算术运算符
- 赋值运算符
- 扩展赋值运算符
- 比较运算符
- 逻辑运算符
- 三目运算符
- 运算符的优先级别
学习目标
知识点 | 要求 |
---|---|
关键字和标识符 | 理解 |
变量和常量 | 掌握 |
八大基本数据类型 | 掌握 |
Scanner键盘输入 | 掌握 |
基本数据类型的类型转换 | 掌握 |
算术运算符 | 掌握 |
赋值运算符 | 掌握 |
扩展赋值运算符 | 掌握 |
比较运算符 | 掌握 |
逻辑运算符 | 掌握 |
三目运算符 | 掌握 |
运算符的优先级别 | 了解 |
1.常量和变量
1.1 关键字&保留字
Java关键字是编程语言中预先定义、具有特定含义的标识符,也称为保留字。这些关键字对Java编译器具有特殊意义,用于表示数据类型或程序结构等核心功能。
abstract | boolean | break | byte | case |
---|---|---|---|---|
catch | char | class | const | continue |
default | do | double | else | enum |
extends | final | finally | float | for |
goto | if | implements | import | instanceof |
int | interface | long | native | new |
package | private | protected | public | return |
short | static | strictfp | super | switch |
synchronized | this | throw | throws | transient |
try | void | volatile | while |
备注:这些关键字不需要刻意去背,后面会慢慢介绍每个关键字的用法。
1.2 标识符
在Java编程中,标识符是用于为变量、类、方法及包等程序元素命名的命名符号。
1.2.1 标识符命名规则
- 标识符由字母(A-Z 和 a-z)、数字(0-9)、下划线(_)和美元符号($)构成;
- 标识符的首字符不能为数字,后续部分可包含字母、下划线、美元符号和数字的任意组合;
- Java 标识符区分大小写,且长度不受限制;
- 标识符不得使用 Java 关键字和保留字。
1.2.2 标识符命名规范
- 类名标识符应采用大驼峰式命名法(PascalCase),即首字母大写且每个单词首字母大写。
例如:Person、GoodStudent - 方法和变量标识符应采用小驼峰式命名法(camelCase),即首字母小写且后续单词首字母大写。
例如:int userName;、public void eatFood(){}
特别说明:由于Java采用Unicode字符集,标识符可使用包括中文在内的多种字符。但为提高代码可读性和维护性,建议避免使用汉字作为标识符。
1.3 变量(Variable)
1.3.1 变量的本质
变量本质上是一个具有确定存储位置的可操作空间,其具体存储值则是不确定的。通过变量名,我们可以访问并操作该存储空间中的内容。
Java作为一门强类型语言,要求所有变量在使用前必须明确声明其数据类型。这种数据类型不仅决定了变量所能存储的值的范围,还直接影响了变量在内存中所占用的存储空间大小。我们可以将内存中的变量形象地比作旅馆的房间,而常量则如同入住这些房间的旅客,每个房间(变量)都有其特定的类型和容量,用于容纳不同类型的旅客(常量)。
1.3.2 变量的声明
变量声明语法:数据类型 变量名;
变量声明本质:就是在内存中开辟一块内存空间,用于存放指定数据类型的数据。
- 声明一个变量
/*** @Author: chenxiezhu* @Date: 2025/5/12 23:08* @Version: v1.0.0* @Description: TODO**/
public class VariableDemo1 {public static void main(String[] args) {// 定义整型变量ageint age;// 定义双精度浮点型变量pricedouble price;}
}
- 同时声明多个变量
语法:数据类型 变量名1, 变量名2, 变量名3;
/*** @Author: chenxiezhu* @Date: 2025/5/12 23:08* @Version: v1.0.0* @Description: TODO**/
public class VariableDemo1 {public static void main(String[] args) {// 声明一个int类型的变量ageint age;// 声明一个float类型的变量double price;// 声明多个int类型的变量int num1, num2, num3;}
}
注意:在同时声明多个变量时,所有变量必须属于同一类型。
1.3.3 变量的赋值
变量赋值的本质是:通过变量名定位对应的内存地址,并将数据存储到该内存区域中。
- 给变量赋值
/*** @Author: chenxiezhu* @Date: 2025/5/12 23:20* @Version: v1.0.0* @Description: TODO**/
public class VariableDemo2 {public static void main(String[] args) {// 声明一个int类型的变量ageint age; // 在内存中分配存储空间// 为age变量赋值age = 23; // 将等号右侧的值赋给左侧的变量}
}
注意:赋值的数据类型必须和声明变量类型一致。
- 声明和赋值同时进行
语法: 数据类型 变量名 = 数据值;
/*** @Author: chenxiezhu* @Date: 2025/5/12 23:20* @Version: v1.0.0* @Description: TODO**/
public class VariableDemo2 {public static void main(String[] args) {int age2 = 23; // 将右侧的值赋给左侧变量}
}
- 同时声明和赋值多个变量
语法:数据类型 变量名1 = 数据值1,变量名2 = 数据值2,变量名3 = 数据值3;
/*** @Author: chenxiezhu* @Date: 2025/5/12 23:20* @Version: v1.0.0* @Description: TODO**/
public class VariableDemo2 {public static void main(String[] args) {// 一次性声明并初始化多个变量(不推荐,影响代码可读性)int num1 = 10, num2 = 20, num3 = 30;}
}
1.3.4 变量总结和提升
变量以"变"为核心特征,其本质在于声明时开辟的内存空间可被重复赋值。
使用变量时需注意以下要点:
1)方法内部声明的变量必须在赋值后才能调用;
2)变量使用需遵循声明优先原则,未经声明的变量名不具备任何意义;
3)命名规范要求变量名采用小写字母开头的驼峰式命名法,且必须符合标识符规则;
4)赋值操作需确保数据类型与变量声明类型严格一致;
5)同一方法内禁止声明多个同名变量。
1.4 常量(Constant)
在编程中,常量指代不可变的固定值,常见示例包括:整型1、浮点型2.1、字符’a’、布尔值true/false、字符串"helloWorld"、空字符串""以及空值null等。
在Java语言中,我们可以通过final关键字来显式声明常量。
语法:final 数据类型 常量名 = 数据值;
常量的核心特性在于其不可变性:一旦完成初始化赋值,其值将始终保持不变,无法被后续程序修改。
/*** @Author: chenxiezhu* @Date: 2025/5/12 23:37* @Version: v1.0.0* @Description: TODO**/
public class ConstantDemo1 {public static void main(String[] args) {final float PI = 3.1415926f;}
}
注意:
- 常量仅允许赋值一次,一旦赋值完成,其值便不可修改。
- 常量名称通常采用大写字母,多个单词之间以下划线分隔,例如:final int MAX_VALUE = 100;
2. 基本数据类型
Java 作为一门强类型语言,要求所有变量在使用前必须明确声明其数据类型。
Java 的数据类型主要分为两大类:基本类型(Primitive Type)和引用类型(Reference Type)。
2.1 整数型
整数型常量可分为以下三种表示形式:
- 十进制整数,如:666,-100等
- 八进制整数,要求以0开头,如:016
- 十六进制整数,要求以0x或0X开头,如:0x1A,0x15
数据类型占用存储空间越大,那么表数的范围也就越大。在开发实践中,应根据具体需求选择合适的数值类型,避免超出表数范围。通常情况下,int类型是最常用的选择。
类型 | 占用存储空间 | 数值范围 |
---|---|---|
byte | 1 字节 | (-128 ~ 127) -27~ 27 - 1 |
short | 2 字节 | (-32768 ~ 32767) -215 ~ 215 - 1 |
int | 4 字节 | (-2147483648 ~ 2147483647) 约 21 亿 -231 ~ 231 - 1 |
long | 8 字节 | -263~ 263 - 1 |
注意:
- 需特别关注数据类型的数值范围,防止因超出范围导致精度损失。
- 整型常量默认采用int类型,如需声明long型常量,可在数值后添加"l"或"L",推荐使用"L"以增强可读性。
2.2 浮点型
在Java中,小数类型统称为浮点类型。
浮点型常量有两种表示形式:
- 十进制形式,如:3.14 或 123.45
- 科学计数法形式,如:314E2(表示31400.0)或314E-2(表示3.14)
浮点类型主要分为两种:
- float(单精度)类型:可精确到7位有效数字,但在多数场景下其精度难以满足需求。
- double(双精度)类型:其数值精度是float类型的两倍,是大多数应用程序的首选。需要注意的是,Java中的浮点型常量默认采用double类型。
类型 | 占用存储空间 | 数值范围 |
---|---|---|
float | 4字节 | -3.403E38 ~ 3.403E38 |
double | 8字节 | -1.798E308 ~ 1.798E308 |
使用浮点型常量时需注意以下事项:
- 浮点型常量默认采用 double 类型存储
- 将浮点型常量赋值给 float 类型变量时,需在常量后添加后缀 “f” 或 “F”
- 不建议直接比较两个浮点数的大小,这种比较方式可能导致精度问题
扩展知识:
整数和浮点数在内存中的存储机制存在显著差异,建议对此感兴趣的同学可以进一步查阅相关资料深入了解。
2.3 布尔型
boolean(布尔型)包含两个取值:true(真)和false(假)。它主要用于逻辑判断,是程序流程控制中的核心数据类型。
扩展知识:
根据Java语言规范,boolean类型的具体存储空间并未明确规定。如需深入了解,建议查阅相关技术文档。
2.4 字符型
2.4.1 字符型
在Java中,字符型数据占用2个字节的内存空间。使用单引号括起来的单个字符被称为字符常量。
如:'A’表示一个字符常量,而"A"则表示一个仅包含单个字符的字符串,两者在Java中具有不同的数据类型和存储方式。
【示例】字符型使用
/*** @Author: chenxiezhu* @Date: 2025/5/13 19:37* @Version: v1.0.0* @Description: TODO**/
public class CharDemo1 {public static void main(String[] args) {char ch1 = 'c'; // 正确:声明并赋值字符'c'char ch2 = '好'; // 正确:声明并赋值字符'好'char ch3 = '6'; // 正确:声明并赋值字符'6'char ch4 = '66'; // 错误:单引号内只能包含单个字符char ch5 = ''; // 错误:单引号内必须包含一个字符char ch6 = "你"; // 错误:字符必须使用单引号,双引号用于字符串}
}
IDEA 会自动检测并提示代码中的错误。
补充说明:char类型用于表示Unicode编码表中的字符,因此它能够完整地表示一个中文字符。
- char类型和int类型的联系和区别
char类型常量在内存中直接存储其对应的Unicode编码值,例如:字符’A’对应65,字符’1’对应49。在特定取值范围内,char类型与int类型可以相互转换并通用。
【示例】char类型和int类型
/*** @Author: chenxiezhu* @Date: 2025/5/13 19:51* @Version: v1.0.0* @Description: TODO**/
public class CharDemo2 {public static void main(String[] args) {char ch1 = 'C'; // Unicode对应的数值为65System.out.println(ch1 + 1); // 输出:68char ch2 = 99; // Unicode对应的字符为'c'System.out.println((char)(ch2 - 32)); // 输出:'C'}
}
char类型与int类型的主要区别:
- 内存占用差异:nt类型在内存中占用4个字节,而char类型仅占用2个字节。
- 数值范围不同:int类型能够表示的数值范围远大于char类型,此外,int类型支持表示负数,而char类型通常用于表示字符或较小的非负整数。
2.4.2 字符集
计算机系统仅能识别0和1,所有信息都以二进制形式存储。对于数值型数据,我们可以直接将其转换为二进制并存入内存,那么字符型数据是如何存储的呢?
实际上,字符本身无法直接转换为二进制。我们在屏幕上看到的英文字母、汉字等字符,都是经过二进制转换后的结果。简单来说,将字符存储在计算机中的规则被称为"编码"。例如,字符’A’可以用十进制数65表示,然后将65转换为二进制存储在内存中。
相反,将计算机中存储的二进制数解析并显示出来的过程称为"解码"。例如,当我们从内存中读取数值65时,就表示读取的字符是’A’。
基于这种"编码"和"解码"机制,人类为不同语言创建了相应的编码表。
以下是几种常见的字符编码表:
- ASCII:美国信息交换标准代码,基于拉丁字母的计算机编码系统,主要用于显示现代英语和西欧语言。
- GBK:全称《汉字内码扩展规范》,是用于表示中文的编码标准。
- Unicode:又称万国码或统一码,旨在解决传统编码方案的局限性。它为每种语言的每个字符设定了统一且唯一的二进制编码,满足跨语言、跨平台的文本转换和处理需求。
Unicode编码占用2个字节,可表示65536个字符,一个中文字符在内存中占用2个字节。
2.4.3 转义字符
Java 语言支持使用转义字符来改变后续字符的特定含义。
转义符 | 含义 | Unicode值 |
---|---|---|
\n | 换行符 | \u000a |
\t | 制表符 | \u0009 |
\" | 双引号 | \u0022 |
\' | 单引号 | \u0027 |
\\ | 反斜杠 | \u005c |
3. Scanner键盘输入
Scanner类位于java.util包中,是Java 5引入的一个用于获取用户输入的类。它提供了读取不同类型数据的便捷方法,大大简化了控制台输入的处理过程。
3.1 导入Scanner包
通过在源文件开头导入java.util.Scanner包,我们便可以在代码中直接使用Scanner类。
import java.util.Scanner;
3.2 初始化Scanner对象
Scanner input = new Scanner(System.in);
3.3 获取输入的数据
从控制台读取用户输入的一行文本,并将其转换为指定类型的数据。
String str = input.next(); // 获取控制台输入的字符串
【示例】
import java.util.Scanner;/*** @Author: chenxiezhu* @Date: 2025/5/14 22:17* @Version: v1.0.0* @Description: TODO**/
public class ScannerDemo {public static void main(String[] args) {// 创建Scanner对象,从标准输入(键盘)获取数据Scanner input = new Scanner(System.in);// 使用Scanner对象的方法读取输入System.out.println("请输入一个字符串:");String number = input.next();System.out.println("您输入的字符串是:" + number);// 关闭Scanner对象input.close();}
}
3.4 Scanner类的常用方法
Scanner提供了多种读取不同数据类型的方法:
方法 | 描述 | 示例 |
---|---|---|
nextInt() | 读取一个整数 | int num = input.nextInt() |
nextDouble() | 读取一个双精度浮点数 | double d = input.nextDouble() |
nextFloat() | 读取一个单精度浮点数 | float f = input.nextFloat() |
nextLong() | 读取一个长整型数 | long l = input.nextLong() |
nextBoolean() | 读取一个布尔值 | boolean b = input.nextBoolean() |
next() | 读取一个字符串,遇到空白字符结束 | String s = input.next() |
nextLine() | 读取一整行文本,遇到换行符结束 | String line = input.nextLine() |
hasNext() | 判断是否还有下一个输入(任意类型) | while(input.hasNext()) {...} |
hasNextInt() | 判断下一个输入是否为整数 | if(input.hasNextInt()) {...} |
hasNextLine() | 判断是否还有下一行 | while(input.hasNextLine()) {...} |
【示例】
import java.util.Scanner;/*** @Author: chenxiezhu* @Date: 2025/5/14 22:23* @Version: v1.0.0* @Description: TODO**/public class ScannerTypeDemo {public static void main(String[] args) {Scanner input = new Scanner(System.in);// 读取整数System.out.println("请输入您的年龄:");int age = input.nextInt();// 读取浮点数System.out.println("请输入您的身高(米):");double height = input.nextDouble();// 读取一个单词(遇到空格停止)System.out.println("请输入您的名字:");input.nextLine(); // 处理换行符String firstName = input.next();// 读取一整行System.out.println("请输入您的全名:");input.nextLine(); // 处理上一个next()方法留下的换行符String fullName = input.nextLine();// 读取布尔值System.out.println("您是否为学生?(true/false)");boolean isStudent = input.nextBoolean();// 输出所有读取的信息System.out.println("\n您输入的信息如下:");System.out.println("年龄:" + age);System.out.println("身高:" + height + "米");System.out.println("名字:" + firstName);System.out.println("全名:" + fullName);System.out.println("是否为学生:" + isStudent);input.close();}
}
【注意事项】
- 调用数据获取方法时,程序将阻塞等待用户输入并按下回车键后才会继续执行后续代码。
- Scanner类未提供直接获取单个字符的方法,即不存在nextChar()方法。
【随堂练习】
- 编写一个程序,通过键盘输入获取矩形的长和宽,并计算该矩形的周长和面积。
4. 基本数据类型转换
在进行赋值或算术运算时,操作数的数据类型必须一致,否则需要进行类型转换。类型转换主要分为两种方式:
- 自动类型转换(隐式)
- 强制类型转换(显示)
基本数据类型之间的转换涉及以下类型:byte、short、int、long、float、double和char,其中boolean类型不参与此类转换。
4.1 自动类型转换
自动类型转换(隐式类型转换)是指当数据从较小容量的数据类型向较大容量的数据类型转换时,系统会自动完成这一过程。
- 由低字节向高字节的转换 byte->short-> char –>int->long->float->double
【赋值运算中的类型转换案例】
/*** @Author: chenxiezhu* @Date: 2025/5/13 21:47* @Version: v1.0.0* @Description: TODO**/
public class TypeCastingDemo1 {public static void main(String[] args) {// 将int类型的值赋值给double数据类型(符合低字节向高字节自动转换)double num = 66;// 将整数常量赋值给byte、 short和char类型变量(不符合低字节向高字节转换)byte b = 110;short s = 119;byte by = 1234; // 编译错误:整数常量超出byte类型的取值范围}
}
将int类型的整型常量赋值给byte、short和char类型变量时,属于自动类型转换的特殊情况,只要该常量的值不超过目标类型的取值范围即可完成赋值。
IDEA提示错误,我们可以点击更多操作(Alt+Enter)修改或者手动修改
算术运算中的类型自动转换原则:
- 如果两个操作数其中有一个是double类型,另一个操作就会转换为double类型,结果为double类型。
- 否则,如果其中一个操作数是float类型,另一个将会转换为float类型,结果为float类型。
- 否则,如果其中一个操作数是long类型,另一个会转换为long类型,结果为long类型。
- 否则,两个操作数都转换为int类型,结果为int类型。
【算术运算中的类型转换案例】
/*** @Author: chenxiezhu* @Date: 2025/5/13 22:39* @Version: v1.0.0* @Description: TODO**/
public class TypePromotionExample {public static void main(String[] args) {// 如果其中一个操作数是double类型,结果是double类型double a = 5.5;int b = 3;double result1 = a + b; // b自动提升为double类型System.out.println("double类型 + int类型的结果:" + result1);// 如果其中一个操作数是float类型,结果是float类型float c = 4.2f;short d = 2;float result2 = c * d; // d自动提升为float类型System.out.println("float类型 * short类型的结果:" + result2);// 如果其中一个操作数是long类型,结果是long类型long e = 1000L;byte f = 10;long result3 = e - f; // f自动提升为long类型System.out.println("long类型 - byte类型的结果: " + result3);// 否则,两个操作数都转换为int类型,结果是int类型char g = 'A'; // ASCII值为65char h = 'B'; // ASCII值为66int result4 = g + h; // g和h自动提升为int类型System.out.println("char类型 + char类型的结果: " + result4);}
}
【常见面试题】
- byte b1 = 11; byte b2 = 12;byte sum = b1 + b2; 和int num1 = 100; int num2 = 300; int sum = num1 + num2;哪一个正确呢?
- 请问说出100000L100000100000和100000100000100000的区别?
- int num1 = 90000; int num2 = 90000; int total = num1 * num2; 请问total的结果是多少?
4.2 强制类型转换
强制类型转换(显示类型转换),主要用于显式的转换一个数值的类型。在有可能丢失信息的情况下进行的转换是通过造型来完成的,但可能造成精度降低或溢出。
语法格式:目标类型 变量 =(目标类型)源类型变量或常量
【示例】
/*** @Author: chenxiezhu* @Date: 2025/5/13 23:26* @Version: v1.0.0* @Description: TODO**/
public class TypeCastExample {public static void main(String[] args) {// 1. 精度损失示例double d = 3.99;int i = (int)d; // 小数部分会被截断System.out.println("将3.99转为int: " + i); // 输出: 3// 2. 数据溢出示例long bigNum = 3000000000L;int smallNum = (int)bigNum; // 超出int范围会溢出System.out.println("将超大long转为int: " + smallNum); // 输出可能是负数// 3. 数据截断示例byte b = (byte)130; // byte范围是-128到127System.out.println("将130转为byte: " + b); // 输出: -126// 4. 字符转换示例char ch = 'A';int ascii = ch; // 自动类型转换char back = (char)ascii; // 显式类型转换System.out.println("字符A的ASCII值: " + ascii);System.out.println("ASCII值65转回字符: " + back);}
}
使用强制类型转换的时候,一定要明确需要强转的数据。
5. 运算符(operator)
5.1 算术运算符
5.1.1 二元运算符
二元运算符是指需要两个操作数进行运算的运算符,包括加(+)、减(-)、乘(*)、除(/)和取模(%)。
运算符 | 名称 | 功能描述 |
---|---|---|
+ | 加 | 计算两个数的和 |
- | 减 | 计算两个数的差 |
* | 乘 | 计算两个数的积 |
/ | 除 | 计算两个数的商 |
% | 取模 | 计算两个数相除的余数 |
【示例】
/*** @Author: chenxiezhu* @Date: 2025/5/14 16:12* @Version: v1.0.0* @Description: TODO**/
public class BinaryOperatorExample {public static void main(String[] args) {
// 定义测试用的变量int a = 10;int b = 3;double x = 10.5;double y = 3.2;// 1. 加法运算符 (+)int sum1 = a + b;double sum2 = x + y;String str1 = "Hello ";String str2 = "World";String strSum = str1 + str2; // 字符串连接System.out.println("加法示例:");System.out.println("整数相加:10 + 3 = " + sum1);System.out.println("小数相加:10.5 + 3.2 = " + sum2);System.out.println("字符串连接:" + strSum);// 2. 减法运算符 (-)int diff1 = a - b;double diff2 = x - y;System.out.println("\n减法示例:");System.out.println("整数相减:10 - 3 = " + diff1);System.out.println("小数相减:10.5 - 3.2 = " + diff2);// 3. 乘法运算符 (*)int product1 = a * b;double product2 = x * y;System.out.println("\n乘法示例:");System.out.println("整数相乘:10 * 3 = " + product1);System.out.println("小数相乘:10.5 * 3.2 = " + product2);// 4. 除法运算符 (/)int quotient1 = a / b; // 整数除法double quotient2 = x / y; // 浮点数除法double quotient3 = (double)a / b; // 整数转换为浮点数后除法System.out.println("\n除法示例:");System.out.println("整数相除:10 / 3 = " + quotient1); // 结果为3(向下取整)System.out.println("小数相除:10.5 / 3.2 = " + quotient2);System.out.println("整数转浮点除法:10.0 / 3 = " + quotient3);// 5. 取模运算符 (%)int remainder1 = a % b;double remainder2 = x % y;System.out.println("\n取模示例:");System.out.println("整数取模:10 % 3 = " + remainder1); // 余数为1System.out.println("小数取模:10.5 % 3.2 = " + remainder2);// 特殊情况示例System.out.println("\n特殊情况示例:");System.out.println("负数取模:-10 % 3 = " + (-10 % 3)); // 负数取模System.out.println("零除:10 / 0.0 = " + (10.0 / 0.0)); // 浮点数除以0try {System.out.println(a / 0); // 整数除以0会抛出异常} catch (ArithmeticException e) {System.out.println("整数除以0会抛出异常:" + e.getMessage());}}
}
【注意事项】
- 加号(+)具有多重功能:既可用于加法运算,也可作为正号或字符串连接符。
- 当两个整数进行除法(/)运算时,结果将自动取整,仅保留整数部分,要得到精确结果,至少需要一个操作数是浮点数。
- 取模运算符(%)可用于整数和浮点数,结果的符号与被除数相同。
- 特殊情况:整数除以0会抛出ArithmeticException异常(异常我们后面再讲),浮点数除以0.0会得到Infinity或NaN,负数的取模运算结果的符号遵循特定规则。
【随堂练习】
- 获取整数2345的千位数、百位数、十位数和个位数。
5.1.2 一元运算符
仅需单个操作数的运算符被称为一元运算符,例如自增运算符(++)和自减运算符( --)等。
运算符 | 名称 | 等价形式 | 运算顺序说明 |
---|---|---|---|
++num | 前置自增 | num = num + 1 | 先自增,后使用新值参与运算 |
num++ | 后置自增 | num = num + 1 | 先使用原值参与运算,后自增 |
--num | 前置自减 | num = num - 1 | 先自减,后使用新值参与运算 |
num-- | 后置自减 | num = num - 1 | 先使用原值参与运算,后自减 |
【示例】
/*** @Author: chenxiezhu* @Date: 2025/5/14 16:36* @Version: v1.0.0* @Description: TODO**/
public class UnaryOperatorExample {public static void main(String[] args) {// 1. 前置自增运算符 (++num)System.out.println("1. 前置自增运算符示例:");int a = 5;int b = ++a; // 先自增,再赋值System.out.println("a = " + a); // 输出:6System.out.println("b = " + b); // 输出:6// 2. 后置自增运算符 (num++)System.out.println("\n2. 后置自增运算符示例:");int c = 5;int d = c++; // 先赋值,再自增System.out.println("c = " + c); // 输出:6System.out.println("d = " + d); // 输出:5// 3. 前置自减运算符 (--num)System.out.println("\n3. 前置自减运算符示例:");int e = 5;int f = --e; // 先自减,再赋值System.out.println("e = " + e); // 输出:4System.out.println("f = " + f); // 输出:4// 4. 后置自减运算符 (num--)System.out.println("\n4. 后置自减运算符示例:");int g = 5;int h = g--; // 先赋值,再自减System.out.println("g = " + g); // 输出:4System.out.println("h = " + h); // 输出:5// 5. 在表达式中使用System.out.println("\n5. 在表达式中的使用示例:");int i = 10;System.out.println("输出 ++i * 2: " + (++i * 2)); // 输出:22 (11*2)System.out.println("此时 i 的值: " + i); // 输出:11int j = 10;System.out.println("输出 j++ * 2: " + (j++ * 2)); // 输出:20 (10*2)System.out.println("此时 j 的值: " + j); // 输出:11// 6. 在循环中的使用System.out.println("\n6. 在循环中的使用示例:");System.out.print("使用前置自增的循环:");for(int k = 0; k < 3; ++k) {System.out.print(k + " ");}System.out.print("\n使用后置自增的循环:");for(int k = 0; k < 3; k++) {System.out.print(k + " ");}// 7. 连续使用自增/自减System.out.println("\n\n7. 连续使用自增/自减示例:");int m = 5;int n = ++m + m++ + --m + m--;System.out.println("m = " + m); // 输出:5System.out.println("n = " + n); // 输出:24// 计算过程:// ++m: m变为6,表达式值为6// m++: 使用6,m变为7,表达式值为6// --m: m变为6,表达式值为6// m--: 使用6,m变为5,表达式值为6// 最终:6 + 6 + 6 + 6 = 24}
}
【建议】
- 在独立语句中,前置和后置运算符效果相同
- 在表达式中使用时要特别注意运算顺序
- 不建议在同一个表达式中多次使用自增/自减运算符,可能导致代码难以理解
- 在循环中,前置和后置的性能差异通常可以忽略不计
- 为了代码清晰度,建议在简单场景(如循环)中使用
- 复杂表达式中应避免使用,改用更清晰的写法
【思考】
- 可以对常量进行递增或递减操作吗?例如:5++或++5。
- int num = 5; num = num++;请问代码执行后num的值为多少?
【随堂练习】
- int x = 7, y = 10; 求 x++ * 3 - --y + y++ / 2 + x-- % 5 - ++y * 2 的值。
5.2 赋值运算符
= 把等号右边的值赋值给左边(一直在用)
【随堂练习】
- 交换两个变量的值(用两种方式实现)。
5.3 扩展赋值运算符
扩展赋值运算符是算术运算符与赋值运算符的组合形式。
运算符 | 用法举例 | 等效的表达式 |
---|---|---|
+= | a += b | a = a + b |
-= | a -= b | a = a - b |
*= | a *= b | a = a * b |
/= | a /= b | a = a / b |
%= | a %= b | a = a % b |
【示例】
//1. 加法赋值运算符 +=
int b = 3;
b += 2; // 等价于 b = b + 2
System.out.println("b = " + b); // 输出: b = 5//2. 减法赋值运算符 -=
int c = 10;
c -= 4; // 等价于 c = c - 4
System.out.println("c = " + c); // 输出: c = 6//3. 乘法赋值运算符 *=
int d = 4;
d *= 3; // 等价于 d = d * 3
System.out.println("d = " + d); // 输出: d = 12//4.除法赋值运算符 /=
int e = 20;
e /= 5; // 等价于 e = e / 5
System.out.println("e = " + e); // 输出: e = 4//. 取模赋值运算符 %=
int f = 17;
f %= 5; // 等价于 f = f % 5
System.out.println("f = " + f); // 输出: f = 2
【随堂练习】
- 获取三个学生的成绩,并计算三个学生成绩的平均分。
【常见面试题】
- short num = 11; num = num + 1; 和short num = 11; num += 1;哪一个正确呢?
- int sum += 30; 请问这行语句语法是否正确???
5.4 比较运算符
比较运算符用来进行比较运算,比较运算符的运算结果是boolean类型。
运算符 | 名称 | 示例 |
---|---|---|
> | 大于 | a > b |
< | 小于 | a < b |
>= | 大于或等于 | a >= b |
<= | 小于或等于 | a <= b |
== | 等于 | a == b |
!= | 不等于 | a != b |
【示例】
/*** @Author: chenxiezhu* @Date: 2025/5/14 17:10* @Version: v1.0.0* @Description: TODO**/
public class ComparisonOperators {public static void main(String[] args) {int a = 10;int b = 5;// 大于 >boolean result1 = a > b;System.out.println("a > b: " + result1); // 输出: true// 小于 <boolean result2 = a < b;System.out.println("a < b: " + result2); // 输出: false// 大于或等于 >=boolean result3 = a >= 10;System.out.println("a >= 10: " + result3); // 输出: true// 小于或等于 <=boolean result4 = b <= 5;System.out.println("b <= 5: " + result4); // 输出: true// 等于 ==boolean result5 = a == b;System.out.println("a == b: " + result5); // 输出: false// 不等于 !=boolean result6 = a != b;System.out.println("a != b: " + result6); // 输出: true// 实际应用示例int score = 85;if (score >= 60) {System.out.println("及格"); // 会输出这行} else {System.out.println("不及格");}}
}
5.5 逻辑运算符
参与逻辑运算的数据类型必须为boolean类型,逻辑运算后的结果也为boolean类型。
5.5.1 与运算、或运算、异或、非运算
运算符 | 名称 | 运算特点(输入→输出) | 运算规律 |
---|---|---|---|
& | 与运算 | true & true = true true & false = false false & true = false false & false = false | 1. 任意一边为 false → 结果为 false 2. 两边均为 true → 结果为 true |
| | 或运算 | true | true = true true | false = true false | true = true false | false = false | 1. 任意一边为 true → 结果为 true 2. 两边均为 false → 结果为 false |
^ | 异或 | true ^ true = false true ^ false = true false ^ true = true false ^ false = false | 1. 两边相同 → 结果为 false 2. 两边不同 → 结果为 true |
! | 非运算 | !true = false !false = true | 单目运算,取反布尔值 |
【示例】
/*** @Author: chenxiezhu* @Date: 2025/5/14 19:50* @Version: v1.0.0* @Description: TODO**/
public class LogicalOperators {public static void main(String[] args) {// 1. 与运算(&)示例System.out.println("=== 与运算(&) ===");System.out.println("true & true = " + (true & true)); // trueSystem.out.println("true & false = " + (true & false)); // falseSystem.out.println("false & true = " + (false & true)); // falseSystem.out.println("false & false = " + (false & false)); // false// 2. 或运算(|)示例System.out.println("\n=== 或运算(|) ===");System.out.println("true | true = " + (true | true)); // trueSystem.out.println("true | false = " + (true | false)); // trueSystem.out.println("false | true = " + (false | true)); // trueSystem.out.println("false | false = " + (false | false)); // false// 3. 异或运算(^)示例System.out.println("\n=== 异或运算(^) ===");System.out.println("true ^ true = " + (true ^ true)); // falseSystem.out.println("true ^ false = " + (true ^ false)); // trueSystem.out.println("false ^ true = " + (false ^ true)); // trueSystem.out.println("false ^ false = " + (false ^ false)); // false// 4. 非运算(!)示例System.out.println("\n=== 非运算(!) ===");System.out.println("!true = " + (!true)); // falseSystem.out.println("!false = " + (!false)); // true}
}
5.5.2 短路与、短路或
&&和&的运算结果相同,但运算过程存在差异:
- &:无论左侧运算结果如何,右侧都会参与运算
- &&:
a. 如果左边运算结果为false,那么右边就不需要参与运算,直接返回结果false。
b. 如果左边运算结果为true,那么继续执行右边的运算,并返回右边运算的结果。
||和|的运算结果相同,但运算过程存在差异:
- |:无论左侧运算结果如何,右侧都会参与运算
- ||:
a. 如果左边运算结果为true,那么右边就不需要参与运算,直接返回结果true。
b. 如果左边运算结果为false,那么继续执行右边的运算,并返回右边运算的结果
运算符 | 名称 | 运算特点 |
---|---|---|
&& | 短路与 | 只要有一个为false ,结果就为false |
|| | 短路或 | 只要有一个为true ,结果就为true |
【示例】
/*** @Author: chenxiezhu* @Date: 2025/5/14 20:09* @Version: v1.0.0* @Description: TODO**/
import java.util.Optional;public class ShortCircuitOperators {public static void main(String[] args) {int x = 10;int y = 20;// ===== 短路与(&&)示例 =====System.out.println("===== 短路与(&&)示例 =====");// 示例1: 左侧为false,右侧不执行System.out.println("\n示例1: 左侧为false,右侧不执行");x = 10;boolean result1 = (x > 15) && (++x > 0);System.out.println("结果: " + result1); // falseSystem.out.println("x的值: " + x); // 10 (x没有增加,说明右侧没有执行)// 示例2: 左侧为true,右侧执行System.out.println("\n示例2: 左侧为true,右侧执行");x = 10;boolean result2 = (x > 5) && (++x > 0);System.out.println("结果: " + result2); // trueSystem.out.println("x的值: " + x); // 11 (x增加了,说明右侧执行了)// 示例3: 与普通与运算符(&)的对比System.out.println("\n示例3: 与普通与运算符(&)的对比");x = 10;boolean result3 = (x > 15) & (++x > 0);System.out.println("结果: " + result3); // falseSystem.out.println("x的值: " + x); // 11 (x增加了,说明右侧执行了)// ===== 短路或(||)示例 =====System.out.println("\n===== 短路或(||)示例 =====");// 示例1: 左侧为true,右侧不执行System.out.println("\n示例1: 左侧为true,右侧不执行");y = 20;boolean result4 = (y > 15) || (++y > 0);System.out.println("结果: " + result4); // trueSystem.out.println("y的值: " + y); // 20 (y没有增加,说明右侧没有执行)// 示例2: 左侧为false,右侧执行System.out.println("\n示例2: 左侧为false,右侧执行");y = 20;boolean result5 = (y < 15) || (++y > 0);System.out.println("结果: " + result5); // trueSystem.out.println("y的值: " + y); // 21 (y增加了,说明右侧执行了)// 示例3: 与普通或运算符(|)的对比System.out.println("\n示例3: 与普通或运算符(|)的对比");y = 20;boolean result6 = (y > 15) | (++y > 0);System.out.println("结果: " + result6); // trueSystem.out.println("y的值: " + y); // 21 (y增加了,说明右侧执行了)}
}
【随堂练习】
- 判断一个数是否在4(包含)~6(不包含)之间;
- 判断一个数是否在4(不包含)~6(包含)之外;
5.6 位运算符(了解一下)
位运算是直接对二进制进行的运算。
5.6.1 <<左移
左移n位,等于在原数据上乘以2的n次方。
例如:3 << 1 = 6
- 00000000 00000000 00000000 00000011
- 0 0000000 00000000 00000000 000000110 左移低位补0
例如:3 << 2 = 12
- 00000000 00000000 00000000 00000011
- 00 000000 00000000 00000000 0000001100
【使用技巧】 3*2可以使用 3<<1来实现,这样做的效率更高。
5.6.2 >>右移
右移n位,等于在源数据上除以2的n次方
例如:6 >> 1 = 3
- 0000 0000 0000 0000 0000 0000 0000 0110
- 00000 0000 0000 0000 0000 0000 0000 011 0 正数则在高位补0,负数则在高位补1
例如:6 >> 2 = 1
- 0000 0000 0000 0000 0000 0000 0000 0110
- 000000 0000 0000 0000 0000 0000 0000 01 10
【使用技巧】 3/2可以使用 3>>1来实现,这样做的效率更高。
5.6.3 >>>无符号右移
>>> 和 >> 操作符类似,但无论值的正负,>>> 都会在高位补 0。
5.6.4 &位运算
位都为1,结果才为1,否则结果为0
例如:12 & 5 = 4
计算过程:
1100 (12)
& 0101 (5)
-------
0100 (4)
从右到左逐位进行与运算:
第1位:0 & 1 = 0
第2位:0 & 0 = 0
第3位:1 & 1 = 1
第4位:1 & 0 = 0
5.6.5 |位运算
位只要有一个为1,那么结果就是1,否则就为0
例如:10 | 6 = 14
计算过程:
1010 (10)
| 0110 (6)
--------
1110 (14)
从右到左逐位进行或运算:
第1位:0 | 0 = 0
第2位:1 | 1 = 1
第3位:0 | 1 = 1
第4位:1 | 0 = 1
5.6.6 ^位运算
两个操作数的位中,相同则结果为0,不同则结果为1
例如:9 ^ 5 = 12
计算过程:
1001 (9)
^ 0101 (5)
----
1100 (12)
5.6.7 ~位运算
如果位为0,结果是1,如果位为1,结果是0
例如:~12 = -13
计算过程:
原始数字 12:
0000 0000 0000 0000 0000 0000 0000 1100
取反后:
1111 1111 1111 1111 1111 1111 1111 0011 (-13)
为什么是-13?
1. 在计算机中,负数以补码形式存储
2. 最高位1表示负数
3. 要得到这个负数的值,需要:
- 取反: 0000 0000 0000 0000 0000 0000 0000 1100
- 加1: +1
得到: 0000 0000 0000 0000 0000 0000 0000 1101 (13)
因此结果是-13
5.7 三目运算符
三目运算符又称为三元运算。
语法格式:条件表达式? 表达式1 : 表达式2
如果条件表达式为true,则取表达式1的值,否则就取表达式2的值。
【示例】
/*** @Author: chenxiezhu* @Date: 2025/5/14 21:08* @Version: v1.0.0* @Description: TODO**/
public class TernaryOperatorExample {public static void main(String[] args) {// 示例1:基础用法 - 判断大小int a = 10;int b = 20;int max = a > b ? a : b;System.out.println("较大的数是:" + max); // 输出:20// 示例2:判断奇偶int number = 7;String result = number % 2 == 0 ? "偶数" : "奇数";System.out.println(number + " 是" + result); // 输出:7 是奇数// 示例3:嵌套使用(虽然可以,但不推荐,会降低代码可读性)int score = 85;String grade = score >= 90 ? "优秀" :score >= 80 ? "良好" :score >= 60 ? "及格" : "不及格";System.out.println("成绩等级:" + grade); // 输出:良好// 示例4:结合字符串boolean isVIP = true;double price = 100.0;double finalPrice = isVIP ? price * 0.8 : price;System.out.println("最终价格:" + finalPrice); // 输出:80.0}
}
【随堂练习】
- 获取两个数的最大值或最小值
5.8 运算符优先级
优先级 | 运算符 | 类别 | 结合性 |
---|---|---|---|
1 | () | 括号运算符 | 由左至右 |
1 | [] | 方括号运算符 | 由左至右 |
2 | ! 、+ (正号)、 - (负号) | 一元运算符 | 由右至左 |
2 | ~ | 位逻辑运算符 | 由右至左 |
2 | ++ 、 -- | 递增/递减运算符 | 由右至左 |
3 | * 、 / 、 % | 算术运算符 | 由左至右 |
4 | + 、 - | 算术运算符 | 由左至右 |
5 | << 、>> | 位移运算符 | 由左至右 |
6 | > 、>= 、< 、<= | 关系运算符 | 由左至右 |
7 | == 、!= | 关系运算符 | 由左至右 |
8 | & | 位与运算符 | 由左至右 |
9 | ^ | 位异或运算符 | 由左至右 |
10 | | | 位或运算符 | 由左至右 |
11 | && | 逻辑与运算符 | 由左至右 |
12 | || | 逻辑或运算符 | 由左至右 |
13 | ?: | 三目条件运算符 | 由右至左 |
14 | = 、+= 、-= 等复合赋值运算符 | 赋值运算符 | 由右至左 |
备注:这些不需要去刻意的记这些优先级,在表达式中建议优先使用小括号来明确运算顺序。