欢迎光临
我们一直在努力

Java变量与运算符详解-完整版

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 命名规则(必须遵守,否则编译报错)

  • 由26个英文字母的大小写、0-9、_、$ 组成
  • 数字不可以开头
  • 不可以使用关键字和保留字,但可以包含关键字和保留字(如 myClass 是合法的)
  • Java严格区分大小写,长度无限制
  • 标识符不能包含空格
  • 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);
    }
    }

    包名/类名/变量名/常量名的命名对比图

    Java - 标识符、包、类、接口、方法、变量、常量的命名规则/规范_java常量的命名规则-CSDN博客


    三、变量的基本使用

    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就是一个位
    使用注意事项
  • 定义 long 类型变量时,赋值需以 L 或 l 作为后缀(推荐大写 L)
  • Java程序中变量通常声明为 int 型,除非不足以表示较大的数才使用 long
  • Java的整型常量默认为 int 型
  • 整数常量还支持十六进制(0x前缀)、八进制(0前缀)、二进制(0b前缀)表示法
  • 代码案例

    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
    使用注意事项
  • float:单精度,尾数可以精确到7位有效数字,很多情况下精度很难满足要求
  • double:双精度,精度是float的两倍,通常采用此类型
  • 定义 float 类型变量时,赋值需以 f 或 F 作为后缀
  • Java的浮点类型常量默认为 double 型
  • 浮点数存在精度丢失问题,金融计算推荐使用 BigDecimal
  • 代码案例

    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:使用转义字符 \\ 将其后的字符转变为特殊含义的字符型常量

  • 常用转义字符表
    转义字符说明Unicode表示
    \\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
    }
    }

    Java 数据类型转换详解:自动转换与强制转换的使用与注意事项_java强制类型转换-CSDN博客


    六、基本数据类型强制类型转换

    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 类型的理解

  • String 类型属于引用数据类型
  • String 类型的变量,可以使用一对 "" 的方式进行赋值
  • String 声明的字符串内部,可以包含0个、1个或者多个字符
  • 7.2 String 与基本数据类型之间的运算

  • 基本数据类型包含8种
  • String 与基本数据类型变量间只能做连接运算,用 + 表示
  • 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?

    这涉及到补码的概念:

  • 6 的原码:0000 0000 0000 0000 0000 0000 0000 0110
  • ~6 按位取反:1111 1111 1111 1111 1111 1111 1111 1001
  • 最高位是 1,说明是负数,需要转回原码看值:
    • 减 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

    执行流程:

  • 先计算条件表达式 a > b(即 10 > 20),结果为 false
  • 因为条件为 false,所以执行 : 后面的表达式2(即 b,值为 20)
  • 将表达式2的值赋给变量 max
  • 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); // 输出:良好

    执行流程(从上到下依次判断):

  • score >= 90 → 85 >= 90 → false → 进入第二个表达式
  • score >= 80 → 85 >= 80 → true → 返回 “良好”
  • 不再继续判断后面的条件
  • 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

    赞(0)
    未经允许不得转载:171主机测评 » Java变量与运算符详解-完整版
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址