Java变量与运算符详解
本文系统梳理Java中变量与运算符的核心知识点,包含关键字、标识符、数据类型、类型转换、String运算等,每个知识点均配有代码案例与易错点提示。
一、关键字(Keyword)
1.1 定义与特点
关键字是被Java语言赋予了特殊含义、用做专门用途的字符串(单词)。
特点:
- 全部关键字都是小写字母
- 不能用作变量名、方法名、类名等标识符
- Java共有50个关键字(含 goto、const 两个保留字)
1.2 关键字速查表
| A | abstract, assert |
| B | boolean, break, byte |
| C | case, catch, char, class, const, continue |
| D | default, do, double |
| E | else, enum, extends |
| F | final, finally, float, for |
| G | goto |
| I | if, implements, import, instanceof, interface |
| L | long |
| N | native |
| P | new, package, private, protected, public |
| R | return |
| S | short, static, strictfp, super, switch, synchronized |
| T | this, throw, throws, transient, try |
| V | void, volatile |
| W | while |
提示:IDE中关键字会以特殊颜色高亮显示,方便识别。
1.3 代码案例
public class KeywordDemo {
public static void main(String[] args) {
// 关键字不能用作变量名,以下代码会编译报错:
// int class = 10; // 错误:class是关键字
// boolean if = true; // 错误:if是关键字
// 正确使用关键字
int age = 25;
double price = 99.9;
boolean isStudent = true;
if (age >= 18) {
System.out.println("成年人");
} else {
System.out.println("未成年人");
}
for (int i = 0; i < 5; i++) {
System.out.println("循环次数:" + i);
}
}
}
1.4 补充:保留字
goto 和 const 是Java的保留字(reserved word),目前并未使用,但未来版本可能会引入。建议不要用作标识符。
二、标识符(Identifier)
2.1 定义
Java中变量、方法、类等要素命名时使用的字符序列,称为标识符。凡是自己可以起名字的都叫做标识符。
2.2 命名规则(必须遵守,否则编译报错)
2.3 命名规范(建议遵守,不遵守不报错)
| 包名 | 多单词组成时所有字母都小写 | com.example.demo |
| 类名/接口名 | 多单词组成时每个单词首字母大写 | StudentInfo, UserManager |
| 变量名/方法名 | 第一个单词首字母小写,后面单词首字母大写(驼峰命名) | studentAge, getUserName() |
| 常量名 | 所有字母大写,多单词用下划线连接 | MAX_SIZE, DEFAULT_TIMEOUT |
2.4 代码案例
public class IdentifierDemo {
// 类名 – 首字母大写
public static void main(String[] args) {
// 变量名 – 驼峰命名
int studentAge = 20; // 合法
int _temp = 10; // 合法(_开头允许)
int $count = 5; // 合法($开头允许)
// int 1name = 1; // 错误:数字开头
// int class = 10; // 错误:使用了关键字
// int my var = 5; // 错误:包含空格
// 常量 – 全大写+下划线
final int MAX_AGE = 150;
System.out.println("学生年龄:" + studentAge);
System.out.println("最大值:" + MAX_AGE);
}
}
包名/类名/变量名/常量名的命名对比图

三、变量的基本使用
3.1 变量的概念
变量是程序中不可或缺的组成单位,是最基本的存储单元。
- 概念:内存中的一块存储区域,该区域的数据可以在同一类型范围内不断变化
- 变量三要素:数据类型 + 变量名 + 存储的值
3.2 变量声明格式
数据类型 变量名 = 变量值;
3.3 变量分类
1. 基本数据类型
- 整数:byte, short, int, long
- 浮点型:float, double
- 字符型:char
- 布尔型:boolean
2. 引用数据类型
- 类(class)
- 数组(array)
- 接口(interface)
- 枚举(enum)
- 注解(annotation)
- 记录(record)—— Java 14+ 引入
3.4 变量使用注意事项
3.5 代码案例
public class VariableDemo {
public static void main(String[] args) {
// 基本数据类型变量
int age = 25;
double height = 175.5;
char grade = 'A';
boolean passed = true;
// 引用数据类型变量
String name = "张三";
int[] scores = {90, 85, 92};
System.out.println("姓名:" + name);
System.out.println("年龄:" + age);
System.out.println("身高:" + height);
System.out.println("成绩等级:" + grade);
System.out.println("是否通过:" + passed);
// 作用域示例
{
int innerVar = 100; // 只在块内有效
System.out.println("块内变量:" + innerVar);
}
// System.out.println(innerVar); // 错误:出了作用域
// 同一作用域不能声明同名变量
// int x = 10;
// int x = 20; // 错误:重复声明
}
}
四、基本数据类型详解
4.1 整型类型:byte / short / int / long
Java各整数类型有固定的表数范围和字段长度,不受具体操作系统影响,以保证Java程序的可移植性。
整型类型对比表
| byte | 1字节 = 8bit | -128 ~ 127 |
| short | 2字节 | -2^15 ~ 2^15-1(-32768 ~ 32767) |
| int | 4字节 | -2^31 ~ 2^31-1(-2147483648 ~ 2147483647) |
| long | 8字节 | -2^63 ~ 2^63-1 |
补充:计算机存储单位
- 字节(Byte):计算机用于计算存储容量的基本单位,1字节 = 8bit
- 位(bit):数据存储的最小单位。二进制数系统中,每个0或1就是一个位
使用注意事项
代码案例
public class IntegerDemo {
public static void main(String[] args) {
// byte范围:-128 ~ 127
byte b = 100;
// byte b2 = 200; // 错误:超出byte范围
// short
short s = 30000;
// int(最常用)
int i = 1000000;
// long – 注意后缀L
long l = 10000000000L;
// 整型常量的不同进制表示
int hex = 0xFF; // 十六进制,等于255
int octal = 017; // 八进制,等于15
int binary = 0b1010; // 二进制,等于10
System.out.println("十六进制0xFF = " + hex); // 255
System.out.println("八进制017 = " + octal); // 15
System.out.println("二进制0b1010 = " + binary); // 10
// int范围边界
System.out.println("int最大值:" + Integer.MAX_VALUE); // 2147483647
System.out.println("int最小值:" + Integer.MIN_VALUE); // -2147483648
// 溢出演示
int overflow = Integer.MAX_VALUE + 1;
System.out.println("int溢出:" + overflow); // -2147483648(从最小值重新开始)
}
}
4.2 浮点类型:float / double
| 单精度 float | 4字节 | -3.403E38 ~ 3.403E38 |
| 双精度 double | 8字节 | -1.798E308 ~ 1.798E308 |
使用注意事项
代码案例
public class FloatDemo {
public static void main(String[] args) {
// double – 最常用
double d1 = 3.1415926535;
double d2 = 10.0;
// float – 需要加f后缀
float f1 = 3.14f;
// float f2 = 3.14; // 错误:3.14默认是double类型
// 科学计数法
double d3 = 6.02e23; // 6.02 * 10^23
// 精度丢失问题(重要!)
System.out.println(0.1 + 0.2); // 输出:0.30000000000000004
// 金融计算应使用BigDecimal
java.math.BigDecimal a = new java.math.BigDecimal("0.1");
java.math.BigDecimal b = new java.math.BigDecimal("0.2");
System.out.println("BigDecimal结果:" + a.add(b)); // 0.3(精确)
}
}

4.3 字符类型:char
char 类型数据用来表示通常意义上"字符",占用两个字节(16位),采用Unicode编码。
字符型变量的三种表现形式
形式1:使用单引号 ' 括起来的单个字符,有且只有一个
char c1 = 'A';
char c2 = '中';
形式2:直接使用Unicode值来表示字符型常量
char c3 = '\\u0041'; // 等于 'A'
char c4 = '\\u4e2d'; // 等于 '中'
形式3:使用转义字符 \\ 将其后的字符转变为特殊含义的字符型常量
常用转义字符表
| \\n | 换行符 | \\u000a |
| \\t | 制表符(Tab) | \\u0009 |
| \\" | 双引号 | \\u0022 |
| \\' | 单引号 | \\u0027 |
| \\\\ | 反斜线 | \\u005c |
| \\b | 退格符 | \\u0008 |
| \\r | 回车符 | \\u000d |
代码案例
public class CharDemo {
public static void main(String[] args) {
// 形式1:单引号括起来的单个字符
char c1 = 'A';
char c2 = '中';
char c3 = '5';
// 形式2:Unicode值
char c4 = '\\u0041'; // 'A'
char c5 = '\\u4e2d'; // '中'
// 形式3:转义字符
char c6 = '\\n'; // 换行
char c7 = '\\t'; // Tab
char c8 = '\\\\'; // 反斜杠
// char本质是整数(Unicode码点)
System.out.println((int)c1); // 65 ('A'的Unicode值)
System.out.println((int)c2); // 20013 ('中'的Unicode值)
// char运算
char c9 = 'a';
System.out.println((int)c9); // 97
System.out.println(c9 + 1); // 98 (char+int = int)
System.out.println((char)(c9 + 1)); // 'b'
// 错误示例:
// char c = 'AB'; // 错误:单引号内只能有一个字符
// char c2 = "A"; // 错误:双引号是String类型
}
}
4.4 布尔类型:boolean
- boolean 类型用来判断逻辑条件,一般用于流程控制语句中
- boolean 类型数据只有两个值:true、false,无其他
- 不可以使用0或者非0的整数代替 false 和 true(这是Java与C/C++的重要区别)
代码案例
public class BooleanDemo {
public static void main(String[] args) {
boolean isAdult = true;
boolean isStudent = false;
// 布尔表达式
boolean result = (10 > 5); // true
boolean result2 = (10 == 5); // false
// 用于流程控制
if (isAdult) {
System.out.println("已成年");
}
// 错误示例(Java不允许):
// if (1) { } // 错误:Java不允许整型作为条件
// boolean b = 1; // 错误:不能用整数给boolean赋值
// 布尔运算
System.out.println(true && false); // false(与)
System.out.println(true || false); // true(或)
System.out.println(!true); // false(非)
}
}
五、基本数据类型变量的自动类型提升
5.1 规则说明
注意:可以做运算的基本数据类型有7种,不包含 boolean 类型。
当容量小的变量与容量大的变量做运算时,结果自动转换为容量大的数据类型。
说明:此时的"容量小"或"容量大",并非指占用的内存空间大小,而是指表示数据的范围的大小。
类型提升顺序:
byte / short / char → int → long → float → double
特别规则:byte、short、char 类型的变量之间做运算,结果为 int 类型。
5.2 代码案例
public class TypePromotionDemo {
public static void main(String[] args) {
byte b = 10;
int i = 20;
long l = 30L;
float f = 3.14f;
double d = 2.718;
// byte + int → 结果自动提升为 int
int result1 = b + i;
// int + long → 结果自动提升为 long
long result2 = i + l;
// long + float → 结果自动提升为 float
float result3 = l + f;
// float + double → 结果自动提升为 double
double result4 = f + d;
// 特别注意:byte/short/char 运算结果为 int
byte b2 = 5;
// byte b3 = b + b2; // 错误!byte+byte = int,需要强制转换
byte b3 = (byte)(b + b2); // 正确:强制转换
// char 运算
char c = 'a';
int result5 = c + 1; // 'a'(97) + 1 = 98
System.out.println(result5); // 98
System.out.println((char)result5); // 'b'
System.out.println("result1=" + result1); // 30
System.out.println("result2=" + result2); // 50
System.out.println("result4=" + result4); // 5.858
}
}

六、基本数据类型强制类型转换
6.1 规则
6.2 代码案例
public class TypeCastDemo {
public static void main(String[] args) {
// 自动类型提升(小→大,无需强转)
double d1 = 100; // int 100 自动提升为 double 100.0
// 强制类型转换(大→小,需要强转)
double d2 = 99.9;
int i1 = (int) d2; // 结果为 99(小数部分直接截断,不是四舍五入!)
System.out.println("强制转换结果:" + i1); // 99
// 精度损失示例
long bigNum = 200L;
byte b = (byte) bigNum; // 200超出byte范围(-128~127),发生溢出
System.out.println("溢出结果:" + b); // -56
// 注意:常量赋值时的特殊规则
byte b2 = 100; // 正确:100在byte范围内,编译器会做常量折叠优化
byte b3 = (byte) 300; // 正确:显式强转,但运行时可能溢出
// 浮点数强制转换
double d3 = 3.99;
int i2 = (int) d3;
System.out.println("浮点转整:" + i2); // 3(截断,不是四舍五入)
}
}
七、String 类型
7.1 String 类型的理解
7.2 String 与基本数据类型之间的运算
7.3 基本数据类型转换为 String 类型
代码案例
public class StringDemo {
public static void main(String[] args) {
// 基本数据类型 + String → 字符串连接
int age = 25;
String result = age + "岁";
System.out.println(result); // "25岁"
// 多个类型连接
String info = "姓名:" + "张三" + ",年龄:" + 25 + ",身高:" + 175.5;
System.out.println(info); // "姓名:张三,年龄:25,身高:175.5"
// 注意运算优先级
int a = 10, b = 20;
System.out.println(a + b + "元"); // "30元"(先算加法,再连接)
System.out.println("" + a + b); // "1020"(先连接再拼接)
System.out.println(a + "元" + b); // "10元20"
// 基本数据类型转String的其他方式
int num = 123;
String s1 = String.valueOf(num); // 方式1:String.valueOf()
String s2 = Integer.toString(num); // 方式2:包装类.toString()
String s3 = num + ""; // 方式3:空字符串连接(最简洁)
}
}
7.4 String 类型转换为基本数据类型
代码案例
public class StringParseDemo {
public static void main(String[] args) {
String s1 = "123";
int i1 = Integer.parseInt(s1);
System.out.println("解析int:" + i1); // 123
String s2 = "3.14";
double d1 = Double.parseDouble(s2);
System.out.println("解析double:" + d1); // 3.14
String s3 = "true";
boolean b1 = Boolean.parseBoolean(s3);
System.out.println("解析boolean:" + b1); // true
// 注意:如果字符串内容不是有效的数字格式,会抛出NumberFormatException
try {
int x = Integer.parseInt("abc");
} catch (NumberFormatException e) {
System.out.println("字符串格式不正确:" + e.getMessage());
}
}
}
7.5 补充:String 的核心特性(重要!)
(1)String 的不可变性
String 对象一旦创建就不可改变。对String的任何修改操作(如 concat、substring、replace 等),实际上都是创建了一个新的String对象,原对象保持不变。
public class StringImmutable {
public static void main(String[] args) {
String s1 = "Hello";
String s2 = s1.concat(" World");
System.out.println(s1); // "Hello"(原字符串未改变)
System.out.println(s2); // "Hello World"(新字符串)
// 字符串常量池机制
String s3 = "Java";
String s4 = "Java";
System.out.println(s3 == s4); // true(指向常量池同一个对象)
String s5 = new String("Java");
System.out.println(s3 == s5); // false(new创建了新对象)
System.out.println(s3.equals(s5)); // true(内容相同)
}
}
(2)== 与 equals() 的区别
| == | 比较内存地址(引用是否指向同一对象) | s1 == s2 |
| equals() | 比较字符串内容是否相同 | s1.equals(s2) |
public class EqualsDemo {
public static void main(String[] args) {
String s1 = "hello";
String s2 = new String("hello");
System.out.println(s1 == s2); // false(不同对象)
System.out.println(s1.equals(s2)); // true(内容相同)
String s3 = "hello";
System.out.println(s1 == s3); // true(常量池复用)
System.out.println(s1.equals(s3)); // true
}
}
(3)频繁字符串拼接应使用 StringBuilder
public class StringBuilderDemo {
public static void main(String[] args) {
// 错误做法:循环中用 + 拼接字符串(每次创建新对象,效率低)
String result = "";
for (int i = 0; i < 1000; i++) {
result += i; // 产生1000个临时String对象
}
// 正确做法:使用StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append(i); // 在原有对象上修改,效率高
}
String finalResult = sb.toString();
}
}
八、Java 算术运算符详解
概述
算术运算符用于进行数学运算。Java 中常见的算术运算符如下:
| + | 加法 | 两个数相加 | 10 + 3 | 13 |
| – | 减法 | 两个数相减 | 10 – 3 | 7 |
| * | 乘法 | 两个数相乘 | 10 * 3 | 30 |
| / | 除法 | 两个数相除 | 10 / 3 | 3 |
| % | 取模/取余 | 求除法余数 | 10 % 3 | 1 |
| ++ | 自增 | 变量加 1 | a++ | a = a + 1 |
| – | 自减 | 变量减 1 | a– | a = a – 1 |
一、+ 加法运算符
1.1 基本用法
+ 最基本的功能就是对两个数值进行加法运算:
int a = 10;
int b = 20;
int c = a + b;
System.out.println(c); // 输出:30
1.2 字符串拼接
Java 中的 + 不仅可以做数学加法,还可以进行字符串拼接。当 + 的一侧是字符串时,另一侧会被自动转换为字符串并拼接:
String name = "Tom";
System.out.println("Hello " + name); // 输出:Hello Tom
1.3 数字与字符串混合运算
当数字和字符串用 + 连接时,数字会先转为字符串再拼接:
System.out.println("年龄:" + 18); // 输出:年龄:18
// 等价于:"年龄:" + "18"
1.4 经典陷阱:运算顺序很重要
+ 在遇到字符串前后的运算顺序会影响结果:
示例一:
System.out.println(10 + 20 + "30");
输出:3030
执行过程:
- 先算 10 + 20 = 30(两个整数相加)
- 再算 30 + "30" = "3030"(数字转字符串拼接)
示例二:
System.out.println("10" + 20 + 30);
输出:102030
执行过程:
- 先算 "10" + 20 = "1020"(字符串拼接)
- 再算 "1020" + 30 = "102030"(继续拼接)
记忆口诀:字符串一旦参与 + 运算,后面的 + 通常都会变成字符串拼接。
二、- 减法运算符
2.1 基本用法
– 用于两个数相减:
int a = 20;
int b = 8;
int c = a – b;
System.out.println(c); // 输出:12
三、* 乘法运算符
3.1 基本用法
* 用于两个数相乘:
int a = 10;
int b = 5;
int c = a * b;
System.out.println(c); // 输出:50
四、/ 除法运算符
/ 是 Java 算术运算符中最容易出错的一个,需要特别注意整数除法和浮点除法的区别。
4.1 整数除法
两个整数相除,结果仍然是整数,小数部分直接被舍弃(不是四舍五入):
int a = 10;
int b = 3;
System.out.println(a / b); // 输出:3(不是 3.333)
4.2 浮点除法
只要参与除法的操作数中至少有一个是浮点数,结果就是浮点数:
System.out.println(10.0 / 3); // 3.3333333333333335
System.out.println(10 / 3.0); // 3.3333333333333335
double a = 10;
double b = 3;
System.out.println(a / b); // 3.3333333333333335
4.3 重要陷阱:double result = 10 / 3
很多初学者会这样写:
double result = 10 / 3;
System.out.println(result); // 输出:3.0(不是 3.333…)
原因:Java 先计算 10 / 3(两个 int 相除得整数 3),然后再把 3 赋值给 double 变量,变成 3.0。计算结果的类型由操作数决定,不是由接收变量决定。
正确写法:
double result = 10.0 / 3; // 写法一:让其中一个操作数为浮点数
double result = (double) 10 / 3; // 写法二:强制类型转换
// 结果:3.3333333333333335
4.4 除数为 0 的情况
整数除以 0 会抛出异常:
int a = 10;
System.out.println(a / 0); // 运行时抛出 ArithmeticException
浮点数除以 0 不会抛异常,而是返回特殊值:
System.out.println(10.0 / 0.0); // Infinity
System.out.println(–10.0 / 0.0); // -Infinity
System.out.println(0.0 / 0.0); // NaN
五、++ 自增运算符
5.1 基本用法
++ 的作用是让变量的值增加 1,等价于 a = a + 1:
int a = 10;
a++;
System.out.println(a); // 输出:11
5.2 前置自增 ++a vs 后置自增 a++
这是 Java 基础中非常重要的考点。两种写法最终都会让变量加 1,但在表达式中参与运算时,返回值不同:
| ++a | 先加 1,再使用 | 新值 |
| a++ | 先使用,再加 1 | 旧值 |
后置自增 a++ 示例:
int a = 10;
int b = a++;
// 执行过程:先把 a 的旧值 10 给 b,然后 a 变成 11
System.out.println(a); // 输出:11
System.out.println(b); // 输出:10
前置自增 ++a 示例:
int a = 10;
int b = ++a;
// 执行过程:a 先加 1 变成 11,然后把新值 11 给 b
System.out.println(a); // 输出:11
System.out.println(b); // 输出:11
5.3 在输出语句中的表现
int a = 10;
System.out.println(a++); // 输出:10(先使用旧值)
System.out.println(a); // 输出:11(变量已自增)
六、– 自减运算符
6.1 基本用法
— 的作用是让变量的值减少 1,等价于 a = a – 1:
int a = 10;
a—;
System.out.println(a); // 输出:9
6.2 前置自减 –a vs 后置自减 a–
规则与自增完全对称:
| –a | 先减 1,再使用 | 新值 |
| a– | 先使用,再减 1 | 旧值 |
后置自减 a– 示例:
int a = 10;
int b = a—;
// 先把 a 的旧值 10 给 b,然后 a 变成 9
System.out.println(a); // 输出:9
System.out.println(b); // 输出:10
前置自减 –a 示例:
int a = 10;
int b = —a;
// a 先减 1 变成 9,然后把新值 9 给 b
System.out.println(a); // 输出:9
System.out.println(b); // 输出:9
记忆口诀:
- a++:先用后加 / ++a:先加后用
- a–:先用后减 / –a:先减后用
七、% 取余运算符
7.1 基本用法
% 表示取余数(模运算):
System.out.println(10 % 3); // 输出:1
// 因为 10 ÷ 3 = 3 余 1
7.2 取余的正负号规则
当参与取余运算的两个数带有正负号时,余数的符号容易搞混。核心规则只有一句话:
余数的符号与被除数(左边的数)一致。
四种情况代码示例:
// 正数 % 正数 → 余数为正
System.out.println(10 % 3); // 输出:1
// 负数 % 正数 → 余数为负(与被除数同号)
System.out.println(–10 % 3); // 输出:-1
// 正数 % 负数 → 余数为正(与被除数同号)
System.out.println(10 % –3); // 输出:1
// 负数 % 负数 → 余数为负(与被除数同号)
System.out.println(–10 % –3); // 输出:-1
记忆口诀:取余符号看被除,余数同号不迷惑。
九、Java 赋值运算符详解
概述
赋值运算符用于给变量赋值。Java 中常见的赋值运算符如下:
| = | 基本赋值 | 将右侧值赋给左侧变量 | a = 10 | — |
| += | 加后赋值 | 自身加右侧值再赋值 | a += 3 | a = a + 3 |
| -= | 减后赋值 | 自身减右侧值再赋值 | a -= 3 | a = a – 3 |
| *= | 乘后赋值 | 自身乘右侧值再赋值 | a *= 3 | a = a * 3 |
| /= | 除后赋值 | 自身除右侧值再赋值 | a /= 3 | a = a / 3 |
| %= | 取余后赋值 | 自身取余右侧值再赋值 | a %= 3 | a = a % 3 |
一、= 基本赋值运算符
1.1 基本用法
= 是 Java 中最基础的赋值运算符,作用是将右侧的值赋给左侧的变量。注意:赋值方向是从右到左。
int a = 10;
int b = 20;
int c = a + b;
System.out.println(c); // 输出:30
1.2 赋值规则
- 等号左边必须是变量(可被赋值的变量),不能是常量或表达式
- 等号右边可以是常量、变量、表达式
- 赋值前需要确保变量已经声明
正确示例:
int a = 10;
int b = a + 5;
a = b * 2;
错误示例:
10 = a; // 错误!左边不能是常量
int a + b = 10; // 错误!左边不能是表达式
1.3 链式赋值
Java 支持链式赋值,多个变量可以同时赋同一个值:
int a = b = c = 10;
// 等价于:
// c = 10;
// b = 10;
// a = 10;
注意:链式赋值中,变量必须先声明类型(只在第一个变量处写类型)。
二、复合赋值运算符
复合赋值运算符将运算和赋值合并为一步,是日常开发中最常用的写法。
2.1 += 加后赋值
int a = 10;
a += 5; // 等价于 a = a + 5
System.out.println(a); // 输出:15
2.2 -= 减后赋值
int a = 10;
a -= 5; // 等价于 a = a – 5
System.out.println(a); // 输出:5
2.3 *= 乘后赋值
int a = 10;
a *= 5; // 等价于 a = a * 5
System.out.println(a); // 输出:50
2.4 /= 除后赋值
int a = 10;
a /= 3; // 等价于 a = a / 3
System.out.println(a); // 输出:3(整数除法,小数部分舍弃)
2.5 %= 取余后赋值
int a = 10;
a %= 3; // 等价于 a = a % 3
System.out.println(a); // 输出:1
三、复合赋值的隐藏类型转换
这是复合赋值运算符最重要也最容易忽略的特性。
3.1 自动类型提升问题
先看下面的代码:
short s = 10;
s = s + 5; // 编译报错!
报错原因:s + 5 中,s 是 short 类型,5 是 int 类型,Java 会自动将 short 提升为 int,所以 s + 5 的结果是 int 类型。把 int 赋值给 short 变量需要强制类型转换。
3.2 复合赋值自带隐式强转
但用复合赋值就不会报错:
short s = 10;
s += 5; // 不会报错!
System.out.println(s); // 输出:15
原因:Java 编译器对复合赋值运算符做了特殊处理,s += 5 等价于 s = (short)(s + 5),自动进行了强制类型转换。
记忆口诀:复合赋值自带隐式强转,short/byte/char 用 += 不用愁。
十、Java 关系运算符(比较运算符)详解
概述
关系运算符用于比较两个值之间的大小或相等关系,运算结果永远是 boolean 类型(true 或 false)。Java 中常见的关系运算符如下:
| == | 等于 | 比较两个值是否相等 | 10 == 10 | true |
| != | 不等于 | 比较两个值是否不相等 | 10 != 5 | true |
| < | 小于 | 左边是否小于右边 | 10 < 20 | true |
| > | 大于 | 左边是否大于右边 | 10 > 5 | true |
| <= | 小于等于 | 左边是否小于或等于右边 | 10 <= 10 | true |
| >= | 大于等于 | 左边是否大于或等于右边 | 10 >= 5 | true |
| instanceof | 类型判断 | 判断对象是否属于某个类/接口 | obj instanceof String | true/false |
注意:前 6 个运算符(==、!=、<、>、<=、>=)的操作数可以是数值类型(int、double 等)和 char 类型;instanceof 专门用于判断对象的数据类型。
一、== 等于运算符
1.1 基本用法(基本数据类型)
== 用于比较两个基本数据类型的值是否相等:
int a = 10;
int b = 10;
System.out.println(a == b); // 输出:true
double x = 3.14;
double y = 3.14;
System.out.println(x == y); // 输出:true
char c1 = 'A';
char c2 = 'A';
System.out.println(c1 == c2); // 输出:true
1.2 重要陷阱:引用类型用 == 比较的是内存地址
这是 Java 面试中最高频的考点之一。对于字符串、数组、对象等引用类型,== 比较的是内存地址(即两个引用是否指向同一个对象),而不是比较内容:
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2); // 输出:false(两个不同的对象,内存地址不同)
System.out.println(s1.equals(s2)); // 输出:true(内容相同)
为什么是 false?
new String("hello") 会在堆内存中创建两个不同的 String 对象,s1 和 s2 分别指向不同的内存地址,所以 == 比较结果为 false。
正确比较字符串内容的方法:
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); // 输出:true(字符串常量池,指向同一个对象)
System.out.println(s1.equals(s2)); // 输出:true(内容比较)
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(s3 == s4); // 输出:false(堆中两个不同对象)
System.out.println(s3.equals(s4)); // 输出:true(内容比较)
记忆口诀:基本类型用 == 比值,引用类型用 equals 比内容,== 比的是地址。
二、!= 不等于运算符
!= 的作用与 == 相反,判断两个值是否不相等:
int a = 10;
int b = 20;
System.out.println(a != b); // 输出:true(10 不等于 20)
String s1 = "hello";
String s2 = "world";
System.out.println(s1 != s2); // 输出:true(两个不同对象的地址不同)
// 注意:引用类型用 != 比较的也是地址
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(s3 != s4); // 输出:true(两个不同对象,地址不同)
// 虽然内容相同,但 != 比的是地址,所以结果为 true
注意:和 == 一样,引用类型用 != 比较的也是内存地址,不是内容。要比较字符串内容是否不同,应该用 !s1.equals(s2)。
三、< > <= >= 大小比较运算符
3.1 基本用法
这四个运算符用于比较数值的大小关系,返回 boolean 值:
int a = 10;
int b = 20;
System.out.println(a < b); // true (10 小于 20)
System.out.println(a > b); // false (10 不大于 20)
System.out.println(a <= 10); // true (10 等于 10,满足"小于或等于")
System.out.println(a >= 20); // false (10 不大于也不等于 20)
// 浮点数也可以比较
double x = 3.14;
double y = 3.15;
System.out.println(x < y); // true
System.out.println(x <= 3.14); // true
3.2 字符也可以比较
char 类型实际上存储的是 Unicode 编码值,所以也可以比较大小:
char c1 = 'A'; // Unicode 值 65
char c2 = 'B'; // Unicode 值 66
System.out.println(c1 < c2); // true (65 < 66)
System.out.println(c1 > 'a'); // false (65 < 97,大写'A'小于小写'a')
System.out.println('a' > 'A'); // true (97 > 65)
// 数字字符也可以比较
System.out.println('3' > '1'); // true ('3'的Unicode值51 > '1'的Unicode值49)
3.3 常见陷阱:Java 不支持链式比较
在数学中我们可以写 1 < x < 10,但在 Java 中不支持链式比较:
int x = 5;
// 错误写法!Java 不支持链式比较
// if (1 < x < 10) { … } // 编译报错
// 正确写法:用逻辑与 && 连接
if (1 < x && x < 10) {
System.out.println("x 在 1 到 10 之间");
}
为什么编译报错?
1 < x < 10 会被 Java 解析为 (1 < x) < 10,即先计算 1 < x 得到 boolean 值(true 或 false),然后再拿 boolean 值和 10 比较,这是非法操作。
记忆口诀:大小比较用 < > <= >=,链式写法 Java 不支持,中间用 && 来连接。
四、instanceof 类型判断运算符
4.1 基本用法
instanceof 是 Java 独有的运算符,用于判断一个对象是否是某个类(或其子类、实现类)的实例:
String str = "Hello";
System.out.println(str instanceof String); // 输出:true
Object obj = "Hello";
System.out.println(obj instanceof String); // 输出:true(String 是 Object 的子类)
Integer num = 100;
System.out.println(num instanceof String); // 输出:false
4.2 继承关系中的 instanceof
instanceof 会检查整个继承链,子类对象 instanceof 父类类型也会返回 true:
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
Animal a1 = new Dog();
Animal a2 = new Cat();
Dog d1 = new Dog();
System.out.println(a1 instanceof Dog); // true (a1 实际指向 Dog 对象)
System.out.println(a1 instanceof Animal);// true (Dog 是 Animal 的子类)
System.out.println(a2 instanceof Dog); // false (a2 实际指向 Cat 对象)
System.out.println(d1 instanceof Animal);// true (Dog 继承自 Animal)
4.3 与 null 比较
null 不是任何类的实例,instanceof 对 null 总是返回 false:
String s = null;
System.out.println(s instanceof String); // 输出:false(不会抛异常)
4.4 实际应用场景:类型转换前的安全判断
instanceof 最常见的用法是在强制类型转换前做类型检查,避免 ClassCastException:
Object obj = "Hello World";
// 先判断类型,再安全转换
if (obj instanceof String) {
String str = (String) obj; // 安全转换
System.out.println(str.toUpperCase()); // 输出:HELLO WORLD
}
// 如果不判断直接转,遇到非 String 对象会抛异常
// String str = (String) obj; // 如果 obj 实际是 Integer,这里会抛 ClassCastException
记忆口诀:instanceof 判类型,转换之前先检查,避免异常更安全。
五、常见错误
错误 1:用 == 比较字符串内容
String a = "hello";
String b = new String("hello");
System.out.println(a == b); // 输出:false(地址不同)
System.out.println(a.equals(b)); // 输出:true(内容相同)
// 正确做法:比较字符串内容永远用 equals()
if (a.equals(b)) {
System.out.println("内容相同");
}
错误 2:混淆 = 和 ==
int a = 5;
if (a = 5) { ... } // 错误!= 是赋值,不是比较
if (a == 5) { ... } // 正确!== 才是比较运算符
// 注意:Java 不会像 C/C++ 那样允许 if(a=5) 这种写法,编译直接报错
错误 3:浮点数直接用 == 比较
double a = 0.1 + 0.2;
double b = 0.3;
System.out.println(a == b); // 输出:false!(浮点数精度问题)
// 0.1 + 0.2 的实际结果是 0.30000000000000004
// 正确做法:用误差范围比较
System.out.println(Math.abs(a – b) < 0.000001); // 输出:true
错误 4:instanceof 左边必须是引用类型
int a = 10;
// System.out.println(a instanceof Integer); // 编译报错!instanceof 左边必须是引用类型
Integer b = 10;
System.out.println(b instanceof Integer); // 正确:输出 true
十一、Java 逻辑运算符详解
概述
逻辑运算符用于对 boolean 类型的值进行逻辑运算,运算结果仍然是 boolean 类型(true 或 false)。Java 中常见的逻辑运算符如下:
| & | 逻辑与(非短路与) | 两边都为 true 才返回 true | true & true | true |
| && | 短路与 | 左边为 false 时不再计算右边 | true && true | true |
| | | 逻辑或(非短路或) | 一边为 true 就返回 true | false | true | true |
| || | 短路或 | 左边为 true 时不再计算右边 | false || true | true |
| ! | 逻辑非 | 取反 | !true | false |
| ^ | 逻辑异或 | 两边不同则返回 true | true ^ false | true |
注意:逻辑运算符的操作数必须是 boolean 类型(不能是数字),这是 Java 与 C/C++ 的重要区别。
一、& 逻辑与(非短路与)
1.1 基本用法
& 是逻辑与运算符,当左右两个操作数都为 true 时,结果才为 true;只要有一个为 false,结果就是 false。
boolean a = true;
boolean b = false;
System.out.println(a & b); // 输出:false(一假即假)
System.out.println(true & true); // 输出:true
System.out.println(true & false); // 输出:false
System.out.println(false & false); // 输出:false
1.2 & 与 && 的区别:是否短路
& 和 && 在逻辑运算结果上完全相同,但关键区别在于是否短路:
- &(非短路与):无论左边是 true 还是 false,都会计算右边
- &&(短路与):如果左边为 false,则不再计算右边(直接返回 false)
代码验证:
public class Test {
public static void main(String[] args) {
System.out.println(isTrue() & isFalse());
}
public static boolean isTrue() {
System.out.println("isTrue 被调用了");
return true;
}
public static boolean isFalse() {
System.out.println("isFalse 被调用了");
return false;
}
}
使用 & 的输出:
isTrue 被调用了
isFalse 被调用了
false
两个方法都被执行了。
如果把 & 改成 &&:
isTrue 被调用了
false
isFalse() 不会被调用,因为 && 发现左边已经是 false,直接返回 false,不再执行右边。
二、&& 短路与
2.1 基本用法
&& 与 & 的逻辑运算结果完全一致,但具备短路特性:当左边表达式为 false 时,不再计算右边表达式,直接返回 false。
int a = 10;
int b = 5;
// 左边为true,继续计算右边
if (a > 5 && b > 3) {
System.out.println("都满足"); // 输出:都满足
}
// 左边为false,右边不再执行
if (a < 5 && b > 3) {
System.out.println("不会执行");
}
System.out.println(b); // b 仍然是 5,右边没执行不影响
2.2 短路的实际价值
短路特性在实际开发中非常有用,常用于空指针防护:
String str = null;
// 危险写法(可能抛 NullPointerException)
// if (str.length() > 0 && str.equals("hello")) { … }
// 正确写法:利用短路特性先判空
if (str != null && str.length() > 0) {
System.out.println("不为空且长度大于0");
}
// 当 str 为 null 时,左边为 false,右边 str.length() 不会执行,避免空指针异常
记忆口诀:&& 和 & 结果一样,但 && 左边假就不算右边,效率更高更安全。日常开发优先用 &&。
三、| 逻辑或(非短路或)
3.1 基本用法
| 是逻辑或运算符,当左右两个操作数中至少有一个为 true 时,结果就是 true;只有两边都为 false 时,结果才为 false。
boolean a = true;
boolean b = false;
System.out.println(a | b); // 输出:true(一真即真)
System.out.println(true | true); // 输出:true
System.out.println(true | false); // 输出:true
System.out.println(false | false); // 输出:false
3.2 | 与 || 的区别:是否短路
与 & 和 && 的关系类似:
- |(非短路或):无论左边是 true 还是 false,都会计算右边
- ||(短路或):如果左边为 true,则不再计算右边(直接返回 true)
代码验证:
public class Test {
public static void main(String[] args) {
System.out.println(isFalse() | isTrue());
}
public static boolean isFalse() {
System.out.println("isFalse 被调用了");
return false;
}
public static boolean isTrue() {
System.out.println("isTrue 被调用了");
return true;
}
}
使用 | 的输出:
isFalse 被调用了
isTrue 被调用了
true
两个方法都被执行了。
如果把 | 改成 ||:
isFalse 被调用了
true
isTrue() 不会被调用,因为 || 发现左边已经是 true,直接返回 true,不再执行右边。
四、|| 短路或
4.1 基本用法
|| 与 | 的逻辑运算结果完全一致,但具备短路特性:当左边表达式为 true 时,不再计算右边表达式,直接返回 true。
String str = "hello";
// 利用短路特性提供默认值
String result = (str != null && str.length() > 0) ? str : "默认值";
System.out.println(result); // 输出:hello
// 如果 str 为 null,使用默认值
str = null;
result = (str != null && str.length() > 0) ? str : "默认值";
System.out.println(result); // 输出:默认值
记忆口诀:|| 和 | 结果一样,但 || 左边真就不算右边,效率更高。日常开发优先用 ||。
五、! 逻辑非
5.1 基本用法
! 是逻辑非运算符(一元运算符),用于取反:true 变 false,false 变 true。
boolean a = true;
boolean b = false;
System.out.println(!a); // 输出:false
System.out.println(!b); // 输出:true
System.out.println(!true); // 输出:false
System.out.println(!false); // 输出:true
5.2 双重否定
!! 相当于不做任何改变,但有时用于将非 boolean 值显式转为 boolean:
// 双重否定等于肯定
System.out.println(!(!true)); // 输出:true
System.out.println(!(!false)); // 输出:false
// 利用 !! 将其他类型显式转为 boolean(Java 中不常用,但 C++ 中常见)
// Java 是强类型语言,不需要这样做
boolean flag = !(5 > 3); // false(5>3 为 true,取反为 false)
boolean flag2 = !!((5 > 3)); // true(Java 不支持 !! 直接用于非boolean表达式)
注意:Java 中 ! 的操作数必须是 boolean 类型,不能对数字使用 !。
六、^ 逻辑异或
6.1 基本用法
^ 是逻辑异或运算符,当两个操作数不同时返回 true,相同时返回 false。
System.out.println(true ^ true); // 输出:false(相同为false)
System.out.println(true ^ false); // 输出:true (不同为true)
System.out.println(false ^ true); // 输出:true (不同为true)
System.out.println(false ^ false); // 输出:false(相同为false)
6.2 异或的真值表
| true | true | false | 相同 → false |
| true | false | true | 不同 → true |
| false | true | true | 不同 → true |
| false | false | false | 相同 → false |
6.3 异或的特性
异或运算有几个非常重要的特性:
特性一:交换律
System.out.println(true ^ false); // true
System.out.println(false ^ true); // true(顺序不影响结果)
特性二:任何值与 true 异或等于取反,与 false 异或不变
System.out.println(true ^ true); // false(与true异或=取反)
System.out.println(false ^ true); // true (与true异或=取反)
System.out.println(true ^ false); // true (与false异或=不变)
System.out.println(false ^ false); // false (与false异或=不变)
特性三:自反性(自己异或自己等于 false)
System.out.println(true ^ true); // false
System.out.println(false ^ false); // false
特性四:与 false 异或不改变原值
boolean flag = true;
System.out.println(flag ^ false); // true(不变)
6.4 异或的实际应用
应用一:简单的值交换(不借助临时变量)
int a = 10;
int b = 20;
a = a ^ b; // a = 10 ^ 20
b = a ^ b; // b = (10 ^ 20) ^ 20 = 10
a = a ^ b; // a = (10 ^ 20) ^ 10 = 20
System.out.println("a = " + a); // 输出:a = 20
System.out.println("b = " + b); // 输出:b = 10
应用二:找出只出现一次的数字(面试高频题)
// 数组中除了一个数字只出现一次外,其他数字都出现两次,找出那个只出现一次的数字
int[] nums = {2, 3, 5, 3, 2};
int result = 0;
for (int num : nums) {
result = result ^ num;
}
System.out.println(result); // 输出:5(5只出现一次,其他都成对抵消了)
// 原理:相同数字异或为0,0与任何数异或等于该数本身
// 2^2 = 0, 3^3 = 0, 剩下 result = 0 ^ 5 = 5
记忆口诀:异或就是不同为真相同为假,自己异或自己是假,与假异或不改变。
十二、Java 位运算符详解:<<、>>、>>>、&、|、^、~
前置知识:位运算符直接对整数在内存中的二进制位进行操作。Java 中整数以补码形式存储,理解补码是掌握位运算的关键。
概述
位运算符用于对整数类型的二进制位进行逐位操作。Java 中常见的位运算符如下:
| << | 左移 | 二进制位全部左移,右边补0 | 6 << 1(110 → 1100) | 12 |
| >> | 右移(有符号) | 二进制位全部右移,左边补符号位 | 6 >> 1(110 → 11) | 3 |
| >>> | 右移(无符号) | 二进制位全部右移,左边补0 | -6 >>> 1 | 大正数 |
| & | 按位与 | 两位都为1则结果为1 | 6 & 3(110 & 011) | 2 |
| | | 按位或 | 有一位为1则结果为1 | `6 | 3`(110 |
| ^ | 按位异或 | 两位不同则结果为1 | 6 ^ 3(110 ^ 011) | 5 |
| ~ | 按位取反 | 0变1,1变0 | ~6 | -7 |
注意:
- 位运算符的操作数必须是整数类型(byte、short、int、long),不能用于 float/double/String/boolean。
- &、|、^ 在逻辑运算符部分已介绍过 boolean 版本的用法,本节重点讲解它们在整数类型上的按位运算用法。
一、<< 左移运算符
1.1 基本用法
<< 将操作数的二进制位全部向左移动指定的位数,右边空出的位用 0 填充,左边溢出的位被丢弃。
int a = 6; // 二进制:0000 0000 0000 0000 0000 0000 0000 0110
int b = a << 1; // 左移1位:0000 0000 0000 0000 0000 0000 0000 1100
System.out.println(b); // 输出:12
1.2 左移的数学含义
左移 n 位等价于乘以 2 的 n 次方:
System.out.println(6 << 1); // 12 (6 × 2¹ = 12)
System.out.println(6 << 2); // 24 (6 × 2² = 24)
System.out.println(6 << 3); // 48 (6 × 2³ = 48)
System.out.println(5 << 2); // 20 (5 × 2² = 20)
1.3 左移的边界情况
当左移导致高位溢出时,数据会丢失:
// int 是 32 位,左移超过 31 位会出问题
int a = 1 << 31; // 得到最小负数:-2147483648(符号位被移到了最高位)
System.out.println(a); // 输出:-2147483648
int b = 1 << 32; // 注意!Java 中 int 左移只取低5位(32 mod 32 = 0),相当于不移!
System.out.println(b); // 输出:1(不是 0!)
// 正确做法:对 long 类型左移
long c = 1L << 32;
System.out.println(c); // 输出:4294967296
记忆口诀:左移一位乘2,左移n位乘2的n次方,注意别溢出。
二、>> 有符号右移运算符
2.1 基本用法
>> 将操作数的二进制位向右移动指定的位数,左边空出的位用符号位(最高位)填充——正数补0,负数补1。因此叫"有符号"右移。
// 正数右移
int a = 6; // 二进制:0000 0000 0000 0000 0000 0000 0000 0110
int b = a >> 1; // 右移1位:0000 0000 0000 0000 0000 0000 0000 0011
System.out.println(b); // 输出:3
// 负数右移(符号位是1,左边补1)
int c = –6; // 二进制(补码):1111 1111 1111 1111 1111 1111 1111 1010
int d = c >> 1; // 右移1位:1111 1111 1111 1111 1111 1111 1111 1101
System.out.println(d); // 输出:-3
2.2 右移的数学含义
右移 n 位等价于除以 2 的 n 次方(向下取整):
System.out.println(12 >> 1); // 6 (12 / 2¹ = 6)
System.out.println(12 >> 2); // 3 (12 / 2² = 3)
System.out.println(12 >> 3); // 1 (12 / 2³ = 1.5 → 向下取整为1)
System.out.println(–12 >> 1); // -6 (-12 / 2 = -6)
System.out.println(–13 >> 1); // -7 (-13 / 2 = -6.5 → 向下取整为-7)
2.3 右移的边界情况
// int 右移超过 31 位同样只取低5位
int a = 100 >> 32; // 相当于 100 >> 0,不移!
System.out.println(a); // 输出:100
// long 右移取低6位(64 mod 64 = 0)
long b = 100L >> 64; // 相当于 100L >> 0,不移!
System.out.println(b); // 输出:100
记忆口诀:右移一位除2,右移n位除2的n次方,负数右移符号位补1。
三、>>> 无符号右移运算符
3.1 基本用法
>>> 是 Java 独有的运算符(C/C++ 没有),将二进制位向右移动指定位数,左边一律补 0,不考虑符号位。因此叫"无符号"右移。
// 正数:>>> 和 >> 结果相同
int a = 6;
System.out.println(a >> 1); // 3
System.out.println(a >>> 1); // 3(正数时两者一样)
// 负数:>>> 和 >> 结果完全不同!
int b = –6; // 补码:1111 1111 1111 1111 1111 1111 1111 1010
System.out.println(b >> 1); // -3(符号位1,左边补1)
System.out.println(b >>> 1); // 2147483645(左边补0,变成大正数)
四、& 按位与运算符
4.1 基本用法
& 对两个整数的二进制位逐位进行与运算:两位都为 1 时结果为 1,否则为 0。
int a = 6; // 二进制:0110
int b = 3; // 二进制:0011
int c = a & b; // 0010 → 十进制 2
System.out.println(c); // 输出:2
五、| 按位或运算符
5.1 基本用法
| 对两个整数的二进制位逐位进行或运算:只要有一位为 1 结果就为 1,两位都为 0 时结果为 0。
int a = 6; // 二进制:0110
int b = 3; // 二进制:0011
int c = a | b; // 0111 → 十进制 7
System.out.println(c); // 输出:7
六、^ 按位异或运算符
6.1 基本用法
^ 对两个整数的二进制位逐位进行异或运算:两位不同时结果为 1,相同时结果为 0。
int a = 6; // 二进制:0110
int b = 3; // 二进制:0011
int c = a ^ b; // 0101 → 十进制 5
System.out.println(c); // 输出:5
七、~ 按位取反运算符
7.1 基本用法
~ 是一元运算符,对操作数的每一位进行取反:0 变 1,1 变 0。
// 以 8 位简化演示(int 实际是 32 位)
// 6 的二进制:0000 0110
// ~6 的二进制:1111 1001 → 补码表示的 -7
System.out.println(~6); // 输出:-7
System.out.println(~0); // 输出:-1(所有位取反:111…111 = -1)
System.out.println(~(–1)); // 输出:0(所有位取反:000…000 = 0)
System.out.println(~(–6)); // 输出:5
7.2 为什么 ~6 = -7?
这涉及到补码的概念:
- 减 1 得反码:1111 1111 1111 1111 1111 1111 1111 1000
- 取反(除符号位)得原码:1000 0000 0000 0000 0000 0000 0000 0111
- 即 ~6 = -7
十三、Java 条件运算符(三元运算符)详解
概述
条件运算符(也称为三元运算符)是 Java 中唯一的三目运算符,它用 ? 和 : 两个符号完成一个简单的条件判断和赋值操作。相比 if-else 语句,三元运算符可以让代码更加简洁。
| 条件表达式?表达式1 :表达式二 | 条件运算符(三元运算符) | 根据条件表达式的真假,选择两个表达式中的一个执行 | a > b ? a : b | 较大值 |
语法格式:
条件表达式 ? 表达式1 : 表达式2
- 条件表达式:必须是 boolean 类型(true 或 false)
- 表达式1:条件为 true 时执行的表达式
- 表达式2:条件为 false 时执行的表达式
- 整个三元运算符的结果就是所执行的那个表达式的值
一、基本用法
1.1 最简单的三元运算
int a = 10;
int b = 20;
// 找出两个数中的较大值
int max = a > b ? a : b;
System.out.println(max); // 输出:20
执行流程:
1.2 在输出语句中直接使用
三元运算符的结果可以直接用于输出或参与其他运算:
int score = 85;
// 直接输出判断结果
System.out.println(score >= 60 ? "及格" : "不及格"); // 输出:及格
// 参与其他运算
int a = 10, b = 20;
int max = (a > b ? a : b) * 2;
System.out.println(max); // 输出:40(先取较大值20,再乘以2)
1.3 给变量赋值
int age = 25;
// 根据年龄判断是否为成年人
String status = age >= 18 ? "成年人" : "未成年人";
System.out.println(status); // 输出:成年人
// 多重判断(用多个三元运算符)
int score = 85;
String grade = score >= 90 ? "优秀" : (score >= 60 ? "及格" : "不及格");
System.out.println(grade); // 输出:及格
二、三元运算符的执行细节
2.1 类型自动提升
三元运算符的两个表达式(表达式1和表达式2)的类型需要兼容,Java 会自动进行类型提升:
// 两个表达式都是 int,结果也是 int
int a = 10 > 5 ? 1 : 2;
System.out.println(a); // 输出:1
// 两个表达式类型不同,自动提升到更高的类型
// int 和 double → 结果提升为 double
double result = 10 > 5 ? 1 : 2.5;
System.out.println(result); // 输出:1.0(int的1被提升为double的1.0)
// String 和 String → 结果就是 String
String msg = 10 > 5 ? "是" : "否";
System.out.println(msg); // 输出:是
2.2 注意:三元运算符是表达式,不是语句
三元运算符有返回值,它本身是一个表达式,所以必须"使用"它的结果(赋值、输出、传入方法等):
// 正确:使用了三元运算符的结果
int x = 10 > 5 ? 1 : 2; // 赋值
System.out.println(10 > 5 ? "yes" : "no"); // 输出
// 错误:没有使用三元运算符的结果(编译报错)
// 10 > 5 ? 1 : 2; // 编译报错!表达式的结果没有被使用
三、嵌套三元运算符
三元运算符可以嵌套使用,实现多条件判断:
3.1 嵌套示例
int score = 85;
// 嵌套三元:判断成绩等级
String grade = score >= 90 ? "优秀"
: score >= 80 ? "良好"
: score >= 60 ? "及格"
: "不及格";
System.out.println(grade); // 输出:良好
执行流程(从上到下依次判断):
3.2 嵌套的注意事项
嵌套三元运算符虽然可以写,但嵌套过深会降低代码可读性,建议最多嵌套 2~3 层,超过的话应该改用 if-else:
// 可读性尚可(2层嵌套)
String result = score >= 90 ? "优秀"
: score >= 60 ? "及格"
: "不及格";
// 可读性差(4层嵌套),建议改用 if-else
// String result = score >= 95 ? "特优"
// : score >= 90 ? "优秀"
// : score >= 80 ? "良好"
// : score >= 60 ? "及格"
// : "不及格";
// 更好的写法:用 if-else



