编程进阶网 编程进阶网
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • C语言入门精通

  • Cpp入门到精通

  • Java入门精通

    • README
    • 入门教程

      • README
      • 基础语法
      • 数据类型
        • 2.1 基本数据
          • 2.1.1 基本数据类型
          • 2.1.2 引用数据类型
          • 2.1.3 基本类型和引用类型区别
          • 2.1.4 综合案例:数据类型信息打印器
          • 2.1.5 训练题
        • 2.2 整数类型
          • 2.2.1 整型列表
          • 2.2.2 整数字面量
          • 2.2.3 整数溢出
          • 2.2.4 综合案例:进制转换工具
          • 2.2.5 训练题
        • 2.3 字符类型
          • 2.3.1 字符类型说明
          • 2.3.2 字符与ASCII
          • 2.3.3 转义字符
          • 2.3.4 综合案例:字符编码查看器
          • 2.3.5 训练题
        • 2.4 浮点类型
          • 2.4.1 浮点类型列表
          • 2.4.2 浮点精度问题
          • 2.4.3 BigDecimal精确计算
          • 2.4.4 综合案例:精确价格比较器
          • 2.4.5 训练题
        • 2.5 布尔类型
          • 2.5.1 布尔类型使用
          • 2.5.2 布尔与C++的区别
          • 2.5.3 综合案例:条件判断验证器
          • 2.5.4 训练题
        • 2.6 变量和常量
          • 2.6.1 变量
          • 2.6.2 常量
          • 2.6.3 变量作用域
          • 2.6.4 综合案例:个人账户信息管理
          • 2.6.5 训练题
        • 2.7 类型转换
          • 2.7.1 自动类型转换
          • 2.7.2 强制类型转换
          • 2.7.3 类型转换注意
          • 2.7.4 综合案例:类型转换安全检查器
          • 2.7.5 训练题
        • 2.8 包装类
          • 2.8.1 包装类介绍
          • 2.8.2 自动装箱拆箱
          • 2.8.3 包装类缓存
          • 2.8.4 常用方法
          • 2.8.5 综合案例:包装类工具箱
          • 2.8.6 训练题
          • 2.8.7 类型转换案例
          • 2.8.8 键盘数据输入
      • 运算符
      • 字符串和数组
      • 流程语句
      • 函数方法
      • 类和对象
      • 继承和多态
      • 接口和抽象类
      • 异常处理
      • 集合框架
      • IO流和File
      • 线程和锁
      • 泛型
      • 注解和反射
    • 综合案例

    • 专栏博客

  • Go入门到精通

  • JavaScript入门

  • CodeX
  • Java入门精通
  • 入门教程
杨充
2026-04-07
目录

数据类型

# 02.数据类型

# 目录介绍

  • 2.1 基本数据
    • 2.1.1 基本数据类型
    • 2.1.2 引用数据类型
    • 2.1.3 基本类型和引用类型区别
    • 2.1.4 综合案例:数据类型信息打印器
    • 2.1.5 训练题
  • 2.2 整数类型
    • 2.2.1 整型列表
    • 2.2.2 整数字面量
    • 2.2.3 整数溢出
    • 2.2.4 综合案例:进制转换工具
    • 2.2.5 训练题
  • 2.3 字符类型
    • 2.3.1 字符类型说明
    • 2.3.2 字符与ASCII
    • 2.3.3 转义字符
    • 2.3.4 综合案例:字符编码查看器
    • 2.3.5 训练题
  • 2.4 浮点类型
    • 2.4.1 浮点类型列表
    • 2.4.2 浮点精度问题
    • 2.4.3 BigDecimal精确计算
    • 2.4.4 综合案例:精确价格比较器
    • 2.4.5 训练题
  • 2.5 布尔类型
    • 2.5.1 布尔类型使用
    • 2.5.2 布尔与C++的区别
    • 2.5.3 综合案例:条件判断验证器
    • 2.5.4 训练题
  • 2.6 变量和常量
    • 2.6.1 变量
    • 2.6.2 常量
    • 2.6.3 变量作用域
    • 2.6.4 综合案例:个人账户信息管理
    • 2.6.5 训练题
  • 2.7 类型转换
    • 2.7.1 自动类型转换
    • 2.7.2 强制类型转换
    • 2.7.3 类型转换注意
    • 2.7.4 综合案例:类型转换安全检查器
    • 2.7.5 训练题
  • 2.8 包装类
    • 2.8.1 包装类介绍
    • 2.8.2 自动装箱拆箱
    • 2.8.3 包装类缓存
    • 2.8.4 常用方法
    • 2.8.5 综合案例:包装类工具箱
    • 2.8.6 训练题
    • 2.8.7 类型转换案例
    • 2.8.8 键盘数据输入

# 2.1 基本数据

# 2.1.1 基本数据类型

Java 有 8 种基本数据类型(Primitive Types),它们直接存储值,而不是引用:

分类 类型 大小(字节) 取值范围
整数 byte 1 -128 ~ 127
整数 short 2 -32768 ~ 32767
整数 int 4 -2^31 ~ 2^31-1
整数 long 8 -2^63 ~ 2^63-1
浮点 float 4 ±3.4e38(6-7位有效数字)
浮点 double 8 ±1.8e308(15-16位有效数字)
字符 char 2 0 ~ 65535(Unicode字符)
布尔 boolean 1(逻辑上) true / false

对比 C++:Java 的基本类型大小是固定的,不受平台影响。而 C++ 的 int 在不同平台可能是 2 字节或 4 字节。Java 的 char 是 2 字节(Unicode),C++ 的 char 是 1 字节(ASCII)。

# 2.1.2 引用数据类型

除了 8 种基本类型,Java 中的其他类型都是引用类型(Reference Types),包括:

  • 类(Class):如 String、Account
  • 接口(Interface):如 List、Runnable
  • 数组(Array):如 int[]、String[]

引用类型的变量存储的是对象在堆内存中的地址引用,而不是对象本身。

// 基本类型:直接存值
int a = 10;

// 引用类型:存储的是对象的地址
String name = "张三";  // name 存储的是 "张三" 这个 String 对象的地址
1
2
3
4
5

# 2.1.3 基本类型和引用类型区别

对比项 基本类型 引用类型
存储位置 栈内存 引用在栈,对象在堆
存储内容 直接存值 存对象的地址
默认值 有默认值(0, false等) 默认值为 null
比较方式 == 比较值 == 比较地址,equals 比较内容
传参方式 值传递(传副本) 值传递(传引用的副本)

对比 C++:C++ 中所有类型都可以在栈上创建,也可以用 new 在堆上创建。Java 的基本类型只能在栈上,对象只能在堆上(通过 new 创建)。

# 2.1.4 综合案例:数据类型信息打印器

编写一个程序,打印 Java 8 种基本数据类型的详细信息(类型名、占用字节、最小值、最大值),并演示基本类型和引用类型的区别。

public class DataTypeInfo {
    public static void main(String[] args) {
        // 打印8种基本数据类型信息
        System.out.println("===== Java 8种基本数据类型 =====");
        System.out.printf("%-10s %-6s %-25s %-25s%n", "类型", "字节", "最小值", "最大值");
        System.out.println("-".repeat(70));
        System.out.printf("%-10s %-6d %-25d %-25d%n", "byte", 1, Byte.MIN_VALUE, Byte.MAX_VALUE);
        System.out.printf("%-10s %-6d %-25d %-25d%n", "short", 2, Short.MIN_VALUE, Short.MAX_VALUE);
        System.out.printf("%-10s %-6d %-25d %-25d%n", "int", 4, Integer.MIN_VALUE, Integer.MAX_VALUE);
        System.out.printf("%-10s %-6d %-25d %-25d%n", "long", 8, Long.MIN_VALUE, Long.MAX_VALUE);
        System.out.printf("%-10s %-6d %-25s %-25s%n", "float", 4, Float.MIN_VALUE, Float.MAX_VALUE);
        System.out.printf("%-10s %-6d %-25s %-25s%n", "double", 8, Double.MIN_VALUE, Double.MAX_VALUE);
        System.out.printf("%-10s %-6d %-25d %-25d%n", "char", 2, (int) Character.MIN_VALUE, (int) Character.MAX_VALUE);
        System.out.printf("%-10s %-6s %-25s %-25s%n", "boolean", "1*", "false", "true");

        // 演示基本类型 vs 引用类型
        System.out.println("\n===== 基本类型 vs 引用类型 =====");
        int a = 100;
        int b = a;        // 值的拷贝
        b = 200;
        System.out.println("基本类型:a=" + a + ", b=" + b);  // a不受影响

        int[] arr1 = {1, 2, 3};
        int[] arr2 = arr1;  // 引用的拷贝(指向同一个数组)
        arr2[0] = 999;
        System.out.println("引用类型:arr1[0]=" + arr1[0] + ", arr2[0]=" + arr2[0]);  // 都变了

        // 默认值演示(成员变量)
        System.out.println("\n===== 默认值演示 =====");
        DefaultValues obj = new DefaultValues();
        obj.printDefaults();
    }
}

class DefaultValues {
    byte byteVal;
    short shortVal;
    int intVal;
    long longVal;
    float floatVal;
    double doubleVal;
    char charVal;
    boolean boolVal;
    String strVal;  // 引用类型

    void printDefaults() {
        System.out.println("byte默认值: " + byteVal);       // 0
        System.out.println("short默认值: " + shortVal);     // 0
        System.out.println("int默认值: " + intVal);         // 0
        System.out.println("long默认值: " + longVal);       // 0
        System.out.println("float默认值: " + floatVal);     // 0.0
        System.out.println("double默认值: " + doubleVal);   // 0.0
        System.out.println("char默认值: [" + charVal + "] (Unicode: " + (int) charVal + ")");  // \u0000
        System.out.println("boolean默认值: " + boolVal);    // false
        System.out.println("String默认值: " + strVal);      // null
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

# 2.1.5 训练题

  1. 填空题:Java 有 ___ 种基本数据类型,分别属于 ___ 大类(整数、浮点、字符、布尔)。

  2. 选择题:以下哪个是引用类型?

    • A. int B. double C. String D. boolean
  3. 判断题:基本类型用 == 比较的是值,引用类型用 == 比较的也是值。( )

  4. 思考题:Java 的基本类型存储在栈内存中,引用类型的对象存储在堆内存中。请思考:为什么 Java 不像 C++ 那样允许对象也在栈上创建?这样设计有什么优缺点?

# 2.2 整数类型

作用:整型变量表示的是整数类型的数据

# 2.2.1 整型列表

数据类型 占用空间 取值范围 默认值
byte 1字节 -128 ~ 127 0
short 2字节 -32768 ~ 32767 0
int 4字节 -2^31 ~ 2^31-1 0
long 8字节 -2^63 ~ 2^63-1 0L

示例:

public class Main {
    public static void main(String[] args) {
        byte b = 127;
        short s = 32767;
        int i = 2147483647;
        long l = 9223372036854775807L;  // long 类型需要加 L 后缀

        System.out.println("byte: " + b);
        System.out.println("short: " + s);
        System.out.println("int: " + i);
        System.out.println("long: " + l);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

对比 C++:Java 没有 unsigned 无符号类型(Java 8 中有部分无符号支持方法),C++ 有 unsigned int、unsigned long 等。

# 2.2.2 整数字面量

Java 支持多种进制的整数字面量:

int decimal = 100;       // 十进制
int binary = 0b1100100;  // 二进制(0b 开头)
int octal = 0144;        // 八进制(0 开头)
int hex = 0x64;          // 十六进制(0x 开头)

// Java 7 开始支持下划线分隔,提高可读性
int million = 1_000_000;
long creditCard = 1234_5678_9012_3456L;
1
2
3
4
5
6
7
8

# 2.2.3 整数溢出

Java 的整数溢出不会报错,而是"绕回"(类似 C++ 的无符号整数溢出行为):

int max = Integer.MAX_VALUE;  // 2147483647
System.out.println(max + 1);  // -2147483648(溢出绕回)
1
2

对比 C++:C++ 中有符号整数溢出是未定义行为(UB),Java 中整数溢出行为是确定的(模运算)。

# 2.2.4 综合案例:进制转换工具

编写一个程序,输入一个十进制整数,输出其各种进制表示,并演示整数溢出和不同整型的范围。

import java.util.Scanner;

public class IntegerConverter {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入一个十进制整数:");
        long input = sc.nextLong();

        // 进制转换
        System.out.println("\n===== 进制转换 =====");
        System.out.println("十进制: " + input);
        System.out.println("二进制: " + Long.toBinaryString(input));
        System.out.println("八进制: " + Long.toOctalString(input));
        System.out.println("十六进制: " + Long.toHexString(input).toUpperCase());

        // 使用下划线分隔提高可读性
        System.out.println("\n===== 字面量写法示例 =====");
        int million = 1_000_000;
        int binary = 0b0000_1111;
        int hex = 0xFF_FF;
        System.out.println("1_000_000 = " + million);
        System.out.println("0b0000_1111 = " + binary);
        System.out.println("0xFF_FF = " + hex);

        // 检查输入值能否装入不同整型
        System.out.println("\n===== 类型适配检查 =====");
        System.out.println("byte  [-128, 127]: " + (input >= Byte.MIN_VALUE && input <= Byte.MAX_VALUE ? "✓ 可存储" : "✗ 超出范围"));
        System.out.println("short [-32768, 32767]: " + (input >= Short.MIN_VALUE && input <= Short.MAX_VALUE ? "✓ 可存储" : "✗ 超出范围"));
        System.out.println("int   [-2^31, 2^31-1]: " + (input >= Integer.MIN_VALUE && input <= Integer.MAX_VALUE ? "✓ 可存储" : "✗ 超出范围"));
        System.out.println("long  [-2^63, 2^63-1]: ✓ 可存储");

        // 溢出演示
        System.out.println("\n===== 整数溢出演示 =====");
        int maxInt = Integer.MAX_VALUE;
        System.out.println("int最大值: " + maxInt);
        System.out.println("int最大值+1: " + (maxInt + 1) + " (溢出!)");
        System.out.println("用long接收: " + (maxInt + 1L) + " (正确)");

        sc.close();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

# 2.2.5 训练题

  1. 选择题:long l = 100; 和 long l = 100L; 有什么区别?

    • A. 完全相同 B. 前者编译错误 C. 前者先创建 int 再自动转为 long D. 后者直接创建 long
  2. 代码题:请写出以下代码的输出:

    int max = Integer.MAX_VALUE;
    System.out.println(max);
    System.out.println(max + 1);
    System.out.println(max + 1L);
    
    1
    2
    3
    4
  3. 思考题:Java 没有 unsigned 无符号整数类型,如果需要存储一个超过 int 正数范围的无符号值(如网络协议中的 32 位无符号整数),Java 中有哪些替代方案?

# 2.3 字符类型

# 2.3.1 字符类型说明

作用:字符型变量用于存储单个字符

Java 的 char 类型占 2 字节,使用 Unicode 编码,可以存储中文字符。

char ch1 = 'A';
char ch2 = '中';     // 可以存储中文
char ch3 = 65;       // 可以用 Unicode 编码值赋值,等价于 'A'
char ch4 = '\u0041'; // 可以用 Unicode 转义,等价于 'A'

System.out.println(ch1);  // A
System.out.println(ch2);  // 中
System.out.println((int) ch1);  // 65
1
2
3
4
5
6
7
8

对比 C++:C++ 的 char 只有 1 字节(ASCII),要存中文需要 wchar_t。Java 的 char 天然支持 Unicode。

# 2.3.2 字符与ASCII

char ch = 'a';
System.out.println((int) ch);  // 97,查看字符对应的编码值

// 字符可以参与运算
char c = 'A';
System.out.println(c + 1);   // 66(int 类型结果)
System.out.println((char)(c + 1));  // B
1
2
3
4
5
6
7

# 2.3.3 转义字符

转义字符 含义
\n 换行
\t 制表符
\\ 反斜杠
\' 单引号
\" 双引号
\uXXXX Unicode 字符

# 2.3.4 综合案例:字符编码查看器

编写一个程序,输入一个字符串,逐字符显示其 Unicode 编码、字符分类(字母/数字/中文/特殊字符),并演示大小写转换。

import java.util.Scanner;

public class CharEncoder {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入一个字符串:");
        String input = sc.nextLine();

        System.out.println("\n===== 字符编码详情 =====");
        System.out.printf("%-6s %-8s %-10s %-12s%n", "字符", "Unicode", "十六进制", "分类");
        System.out.println("-".repeat(40));

        int letterCount = 0, digitCount = 0, chineseCount = 0, otherCount = 0;

        for (int i = 0; i < input.length(); i++) {
            char ch = input.charAt(i);
            String category;
            if (Character.isUpperCase(ch)) {
                category = "大写字母";
                letterCount++;
            } else if (Character.isLowerCase(ch)) {
                category = "小写字母";
                letterCount++;
            } else if (Character.isDigit(ch)) {
                category = "数字";
                digitCount++;
            } else if (ch >= '\u4e00' && ch <= '\u9fff') {
                category = "中文";
                chineseCount++;
            } else {
                category = "特殊字符";
                otherCount++;
            }
            System.out.printf("%-6c %-8d \\u%-8s %-12s%n", ch, (int) ch,
                    String.format("%04X", (int) ch), category);
        }

        // 统计信息
        System.out.println("\n===== 统计信息 =====");
        System.out.println("字母: " + letterCount + ", 数字: " + digitCount
                + ", 中文: " + chineseCount + ", 其他: " + otherCount);

        // 大小写转换演示
        System.out.println("\n===== 大小写转换 =====");
        StringBuilder upper = new StringBuilder();
        StringBuilder lower = new StringBuilder();
        for (char ch : input.toCharArray()) {
            upper.append(Character.toUpperCase(ch));
            lower.append(Character.toLowerCase(ch));
        }
        System.out.println("全部大写: " + upper);
        System.out.println("全部小写: " + lower);

        // 转义字符演示
        System.out.println("\n===== 转义字符演示 =====");
        System.out.println("换行符: Hello\\nWorld → Hello\nWorld");
        System.out.println("制表符: A\\tB → A\tB");
        System.out.println("反斜杠: \\\\ → \\");

        sc.close();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

# 2.3.5 训练题

  1. 代码题:请写出以下代码的输出:

    char c1 = 'A';
    char c2 = 'a';
    System.out.println(c1 + c2);
    System.out.println("" + c1 + c2);
    
    1
    2
    3
    4
  2. 实践题:编写代码,将用户输入的一个小写字母转换为大写字母(提示:利用 ASCII 码差值)。

  3. 思考题:Java 的 char 是 2 字节(UTF-16),可以存储大部分中文字符。但对于一些生僻汉字(如 emoji 表情),一个 char 能存下吗?Java 如何处理这种情况?

# 2.4 浮点类型

作用:用于表示小数

# 2.4.1 浮点类型列表

数据类型 占用空间 精度(有效数字) 默认值
float 4字节 6-7 位 0.0f
double 8字节 15-16 位 0.0
float f = 3.14f;    // float 必须加 f 后缀
double d = 3.14;    // 默认是 double 类型
double d2 = 3.14d;  // 加 d 后缀(可选)

System.out.println(f);   // 3.14
System.out.println(d);   // 3.14
1
2
3
4
5
6

注意:浮点字面量默认是 double 类型,赋值给 float 变量需要加 f 后缀,否则编译报错。

# 2.4.2 浮点精度问题

浮点数在计算时可能会产生精度损失:

System.out.println(0.1 + 0.2);  // 0.30000000000000004,不是 0.3!
System.out.println(1.0 - 0.9);  // 0.09999999999999998

// 不要用 == 比较浮点数
double a = 0.1 + 0.2;
double b = 0.3;
System.out.println(a == b);  // false!
// 正确做法:使用误差范围比较
System.out.println(Math.abs(a - b) < 1e-9);  // true
1
2
3
4
5
6
7
8
9

# 2.4.3 BigDecimal精确计算

对于需要精确计算的场景(如金融计算),使用 BigDecimal:

import java.math.BigDecimal;

BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
BigDecimal result = a.add(b);
System.out.println(result);  // 0.3(精确结果)

// 注意:必须用字符串构造 BigDecimal
// new BigDecimal(0.1) 仍然有精度问题!
1
2
3
4
5
6
7
8
9

对比 C++:C++ 标准库没有 BigDecimal,需要自己实现或使用第三方库。Java 标准库就内置了。

# 2.4.4 综合案例:精确价格比较器

编写一个程序,演示浮点数精度问题、BigDecimal 正确用法和错误用法的对比,以及特殊浮点值的处理。

import java.math.BigDecimal;
import java.math.RoundingMode;

public class PrecisionCompare {
    public static void main(String[] args) {
        // 精度问题演示
        System.out.println("===== 浮点精度陷阱 =====");
        double a = 0.1 + 0.2;
        double b = 0.3;
        System.out.println("0.1 + 0.2 = " + a);           // 0.30000000000000004
        System.out.println("0.3       = " + b);
        System.out.println("== 比较: " + (a == b));         // false
        System.out.println("误差比较: " + (Math.abs(a - b) < 1e-9));  // true

        // BigDecimal 正确 vs 错误用法
        System.out.println("\n===== BigDecimal 正确 vs 错误 =====");
        BigDecimal wrong = new BigDecimal(0.1);            // 用double构造(不精确)
        BigDecimal right = new BigDecimal("0.1");          // 用字符串构造(精确)
        System.out.println("new BigDecimal(0.1)   = " + wrong);
        System.out.println("new BigDecimal(\"0.1\") = " + right);

        // 模拟购物车价格计算
        System.out.println("\n===== 购物车精确计算 =====");
        String[][] items = {
            {"Java编程思想", "89.50", "1"},
            {"机械键盘",     "299.99", "1"},
            {"USB数据线",    "9.90", "3"},
        };

        BigDecimal total = BigDecimal.ZERO;
        for (String[] item : items) {
            BigDecimal price = new BigDecimal(item[1]);
            BigDecimal qty = new BigDecimal(item[2]);
            BigDecimal subtotal = price.multiply(qty);
            total = total.add(subtotal);
            System.out.printf("  %s: ¥%s × %s = ¥%s%n", item[0], item[1], item[2], subtotal);
        }
        System.out.println("  小计: ¥" + total);

        // 打折和四舍五入
        BigDecimal discount = new BigDecimal("0.88");
        BigDecimal discounted = total.multiply(discount).setScale(2, RoundingMode.HALF_UP);
        System.out.println("  88折后: ¥" + discounted);

        // 特殊浮点值
        System.out.println("\n===== 特殊浮点值 =====");
        System.out.println("1.0 / 0   = " + (1.0 / 0));     // Infinity
        System.out.println("-1.0 / 0  = " + (-1.0 / 0));    // -Infinity
        System.out.println("0.0 / 0   = " + (0.0 / 0));     // NaN
        System.out.println("NaN == NaN: " + (Double.NaN == Double.NaN));  // false
        System.out.println("isNaN检测: " + Double.isNaN(0.0 / 0));       // true
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

# 2.4.5 训练题

  1. 代码题:请预测以下代码的输出结果:

    System.out.println(1.0 / 0);
    System.out.println(0.0 / 0);
    System.out.println(Double.isNaN(0.0 / 0));
    
    1
    2
    3
  2. 实践题:使用 BigDecimal 计算 10.00 元 × 0.7 折扣 - 3.50 元优惠券 的最终价格,结果保留两位小数。

  3. 思考题:new BigDecimal(0.1) 和 new BigDecimal("0.1") 的结果不同,为什么?在使用 BigDecimal 时有哪些常见的陷阱?

# 2.5 布尔类型

# 2.5.1 布尔类型使用

作用:布尔数据类型代表真或假的值

boolean flag1 = true;
boolean flag2 = false;
boolean result = (10 > 5);  // true

System.out.println(flag1);   // true
System.out.println(result);  // true
1
2
3
4
5
6

# 2.5.2 布尔与C++的区别

Java 的 boolean 和 C++ 的 bool 有一个重要区别:

// Java:boolean 不能和 int 互转
boolean b = true;
// int i = b;        // 编译错误!
// boolean b2 = 1;   // 编译错误!
// if (1) {}         // 编译错误!if 条件必须是 boolean

// C++:bool 可以和 int 互转
// bool b = true;
// int i = b;     // OK,i = 1
// bool b2 = 1;   // OK,b2 = true
// if (1) {}       // OK
1
2
3
4
5
6
7
8
9
10
11

Java 更严格,布尔类型就是布尔类型,不能与整数混用,这样可以避免很多 C++ 中常见的错误(如 if (a = 1) 写成赋值)。

# 2.5.3 综合案例:条件判断验证器

编写一个程序,演示布尔类型在条件判断、逻辑运算中的正确使用方式,以及 Java 和 C++ 在布尔类型上的关键差异。

public class BooleanValidator {
    public static void main(String[] args) {
        // 布尔类型基本使用
        System.out.println("===== 布尔类型基本使用 =====");
        boolean isJava = true;
        boolean isCpp = false;
        System.out.println("isJava: " + isJava);
        System.out.println("isCpp: " + isCpp);

        // 比较运算产生布尔值
        int score = 85;
        boolean passed = score >= 60;
        boolean excellent = score >= 90;
        System.out.println("成绩 " + score + " 分, 及格: " + passed + ", 优秀: " + excellent);

        // 逻辑运算
        System.out.println("\n===== 逻辑运算 =====");
        boolean hasTicket = true;
        boolean hasID = true;
        boolean isVIP = false;

        boolean canEnter = (hasTicket && hasID) || isVIP;
        System.out.println("有票: " + hasTicket + ", 有证件: " + hasID + ", VIP: " + isVIP);
        System.out.println("能否入场: " + canEnter);

        // 短路求值演示
        System.out.println("\n===== 短路求值 =====");
        int x = 10;
        boolean result = (x > 5) || checkValue(x);  // 短路,不会调用checkValue
        System.out.println("短路或(||): x>5为true, checkValue未被调用, result=" + result);

        result = (x < 5) && checkValue(x);  // 短路,不会调用checkValue
        System.out.println("短路与(&&): x<5为false, checkValue未被调用, result=" + result);

        // Java vs C++ 差异
        System.out.println("\n===== Java vs C++ 差异 =====");
        System.out.println("Java: boolean不能与int互转");
        System.out.println("  boolean b = true;");
        System.out.println("  // int i = b;      → 编译错误!");
        System.out.println("  // boolean b2 = 1; → 编译错误!");
        System.out.println("  // if (1) {}       → 编译错误!");
        System.out.println("C++: bool可以与int互转");
        System.out.println("  bool b = true; int i = b;  → OK, i=1");
        System.out.println("  if (1) {}                  → OK");

        // 布尔类型的包装类
        System.out.println("\n===== Boolean包装类 =====");
        Boolean flag1 = Boolean.valueOf(true);
        Boolean flag2 = Boolean.valueOf("true");
        Boolean flag3 = Boolean.valueOf("yes");  // 非"true"字符串都是false
        System.out.println("Boolean.valueOf(true): " + flag1);
        System.out.println("Boolean.valueOf(\"true\"): " + flag2);
        System.out.println("Boolean.valueOf(\"yes\"): " + flag3);  // false
    }

    static boolean checkValue(int val) {
        System.out.println("  checkValue被调用了!");
        return val > 0;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

# 2.5.4 训练题

  1. 判断题:boolean b = 1; 在 Java 中可以编译通过。( )

  2. 代码题:以下代码在 Java 中能编译通过吗?如果不能,说明原因:

    int x = 10;
    if (x) {
        System.out.println("true");
    }
    
    1
    2
    3
    4
  3. 思考题:Java 的 boolean 在 JVM 规范中并没有规定固定大小。请查阅资料,说明 boolean 类型在 JVM 中实际占用多少字节?为什么 boolean[] 数组中每个元素占 1 字节?

# 2.6 变量和常量

# 2.6.1 变量

作用:给一段指定的内存空间起名,方便操作这段内存。

语法:数据类型 变量名 = 初始值;

public class Main {
    public static void main(String[] args) {
        int a = 10;
        System.out.println("a = " + a);

        // Java 10 引入 var 关键字(类似 C++ 的 auto)
        var name = "张三";   // 编译器自动推断为 String
        var count = 100;     // 编译器自动推断为 int
    }
}
1
2
3
4
5
6
7
8
9
10

# 2.6.2 常量

作用:用于记录程序中不可更改的数据

Java 使用 final 关键字定义常量:

public class Main {
    // 类级别常量(通常配合 static 使用)
    static final double PI = 3.14159;
    static final int MAX_SIZE = 100;

    public static void main(String[] args) {
        // 局部常量
        final int month = 12;
        System.out.println("一年有 " + month + " 个月");
        // month = 24;  // 编译错误,常量不可修改
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

对比 C++:C++ 使用 const 或 #define 定义常量,Java 使用 final。Java 没有 #define(Java 没有预处理器)。

# 2.6.3 变量作用域

public class Main {
    static int classVar = 10;      // 类变量(静态变量)

    int instanceVar = 20;          // 实例变量

    public void method() {
        int localVar = 30;         // 局部变量
        System.out.println(localVar);
    }

    public static void main(String[] args) {
        // 局部变量必须先初始化才能使用
        int a;
        // System.out.println(a);  // 编译错误:变量 a 可能未初始化
        a = 10;
        System.out.println(a);     // OK
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

对比 C++:C++ 的局部变量不初始化时值是随机的(未定义行为),Java 编译器会强制要求局部变量在使用前初始化。

# 2.6.4 综合案例:个人账户信息管理

编写一个程序,综合运用变量、常量、var 推断和作用域知识,模拟一个简单的个人账户系统。

public class AccountManager {
    // 类级别常量
    static final double TAX_RATE = 0.03;        // 税率 3%
    static final int MAX_NICKNAME_LENGTH = 10;   // 昵称最大长度
    static final String CURRENCY = "CNY";        // 货币单位

    // 实例变量(有默认值)
    String name;
    double balance;
    int level;

    public AccountManager(String name, double balance) {
        this.name = name;
        this.balance = balance;
        this.level = 1;  // 默认等级
    }

    public void deposit(double amount) {
        // 局部变量必须初始化
        final double MAX_DEPOSIT = 50000.0;  // 局部常量
        if (amount > MAX_DEPOSIT) {
            System.out.println("单笔存款不能超过 " + MAX_DEPOSIT + " 元");
            return;
        }
        balance += amount;
        System.out.printf("存款 %.2f 元, 余额: %.2f %s%n", amount, balance, CURRENCY);
    }

    public void withdraw(double amount) {
        // 使用 var 推断类型(Java 10+)
        var fee = amount * TAX_RATE;  // 编译器推断为 double
        var totalDeduct = amount + fee;
        if (totalDeduct > balance) {
            System.out.println("余额不足! 需要: " + totalDeduct + ", 当前: " + balance);
            return;
        }
        balance -= totalDeduct;
        System.out.printf("取款 %.2f 元, 手续费 %.2f 元, 余额: %.2f %s%n",
                amount, fee, balance, CURRENCY);
    }

    public void showInfo() {
        System.out.println("===== 账户信息 =====");
        System.out.println("姓名: " + name);
        System.out.printf("余额: %.2f %s%n", balance, CURRENCY);
        System.out.println("等级: " + level);
        System.out.println("税率: " + (TAX_RATE * 100) + "%");
    }

    public static void main(String[] args) {
        // 变量声明和初始化
        var account = new AccountManager("张三", 10000.0);
        account.showInfo();

        System.out.println();
        account.deposit(5000);
        account.withdraw(2000);

        System.out.println();
        account.showInfo();

        // 作用域演示
        System.out.println("\n===== 作用域演示 =====");
        {
            int blockVar = 100;  // 块级作用域变量
            System.out.println("块内 blockVar = " + blockVar);
        }
        // System.out.println(blockVar);  // 编译错误:超出作用域

        for (int i = 0; i < 3; i++) {
            var msg = "循环 " + i;  // 每次循环创建新的局部变量
            System.out.println(msg);
        }
        // System.out.println(i);  // 编译错误:i 超出作用域
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

# 2.6.5 训练题

  1. 改错题:以下代码有什么问题?

    public class Test {
        public static void main(String[] args) {
            final int MAX;
            MAX = 100;
            MAX = 200;
            System.out.println(MAX);
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
  2. 填空题:Java 中类变量(static)和实例变量有默认值,但 ___ 变量必须在使用前手动初始化。

  3. 实践题:编写一个程序,定义以下变量并输出:一个 int 类型的局部变量、一个 final 常量、一个使用 var 推断类型的变量。

  4. 思考题:Java 使用 final 定义常量,C++ 使用 const。Java 中有没有类似 C++ constexpr(编译期常量)的概念?static final 和 final 有什么区别?

# 2.7 类型转换

# 2.7.1 自动类型转换

自动类型转换(隐式转换):小类型自动转为大类型,不会丢失数据。

转换路线:byte → short → int → long → float → double

byte b = 10;
int i = b;        // 自动转换,byte → int
long l = i;       // 自动转换,int → long
double d = l;     // 自动转换,long → double

char c = 'A';
int ci = c;       // 自动转换,char → int(值为65)
1
2
3
4
5
6
7

# 2.7.2 强制类型转换

强制类型转换(显式转换):大类型转为小类型,可能丢失数据。

double d = 3.99;
int i = (int) d;       // 强制转换,i = 3(截断小数部分)

int big = 130;
byte b = (byte) big;   // 强制转换,b = -126(溢出)

System.out.println(i);  // 3
System.out.println(b);  // -126
1
2
3
4
5
6
7
8

# 2.7.3 类型转换注意

  1. boolean 不参与任何类型转换。
  2. byte、short、char 在运算时自动提升为 int。
  3. 强制转换可能导致精度丢失或数据溢出。
byte a = 10;
byte b = 20;
// byte c = a + b;    // 编译错误!a + b 结果是 int
byte c = (byte)(a + b);  // 需要强制转换
int d = a + b;            // 或者用 int 接收
1
2
3
4
5

# 2.7.4 综合案例:类型转换安全检查器

编写一个程序,输入一个数值,检测其在各种类型转换时是否安全(是否会丢失精度或溢出),并演示自动转换和强制转换的区别。

import java.util.Scanner;

public class TypeCastChecker {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入一个数值(支持小数):");
        double input = sc.nextDouble();

        System.out.println("\n===== 类型转换安全检查 =====");

        // double → float
        float asFloat = (float) input;
        boolean floatSafe = (double) asFloat == input;
        System.out.printf("double→float: %.15f → %.7f %s%n", input, asFloat,
                floatSafe ? "[安全]" : "[精度丢失!]");

        // double → long
        long asLong = (long) input;
        boolean longSafe = (input == Math.floor(input)) && input >= Long.MIN_VALUE && input <= Long.MAX_VALUE;
        System.out.printf("double→long: %f → %d %s%n", input, asLong,
                longSafe ? "[安全]" : "[截断小数或溢出!]");

        // double → int
        boolean intSafe = (input == Math.floor(input)) && input >= Integer.MIN_VALUE && input <= Integer.MAX_VALUE;
        int asInt = (int) input;
        System.out.printf("double→int: %f → %d %s%n", input, asInt,
                intSafe ? "[安全]" : "[截断小数或溢出!]");

        // double → short
        boolean shortSafe = (input == Math.floor(input)) && input >= Short.MIN_VALUE && input <= Short.MAX_VALUE;
        short asShort = (short) asInt;
        System.out.printf("double→short: %f → %d %s%n", input, asShort,
                shortSafe ? "[安全]" : "[数据丢失!]");

        // double → byte
        boolean byteSafe = (input == Math.floor(input)) && input >= Byte.MIN_VALUE && input <= Byte.MAX_VALUE;
        byte asByte = (byte) asInt;
        System.out.printf("double→byte: %f → %d %s%n", input, asByte,
                byteSafe ? "[安全]" : "[数据丢失!]");

        // 自动类型转换链演示
        System.out.println("\n===== 自动转换链 =====");
        byte b = 42;
        short s = b;      // byte → short
        int i = s;        // short → int
        long l = i;       // int → long
        float f = l;      // long → float (可能丢精度!)
        double d = f;     // float → double
        System.out.printf("byte(%d) → short(%d) → int(%d) → long(%d) → float(%f) → double(%f)%n",
                b, s, i, l, f, d);

        // long → float 精度丢失演示
        System.out.println("\n===== long→float 精度丢失 =====");
        long bigLong = 123456789123456789L;
        float bigFloat = bigLong;  // 自动转换但丢精度
        System.out.println("long值: " + bigLong);
        System.out.println("转float: " + bigFloat);
        System.out.println("转回long: " + (long) bigFloat);
        System.out.println("精度丢失: " + (bigLong != (long) bigFloat));

        // byte运算自动提升为int
        System.out.println("\n===== byte运算提升 =====");
        byte x = 10, y = 20;
        // byte z = x + y;  // 编译错误! x+y结果是int
        int z = x + y;       // 用int接收
        byte z2 = (byte)(x + y);  // 或强制转换
        System.out.println("byte + byte → int: " + z);
        System.out.println("强制转回byte: " + z2);

        sc.close();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

# 2.7.5 训练题

  1. 代码题:请预测以下代码的输出:

    byte a = 10, b = 20;
    // byte c = a + b;  // 编译错误还是正确?
    int c = a + b;
    System.out.println(c);
    
    short s = 100;
    s += 200;  // 编译错误还是正确?
    System.out.println(s);
    
    1
    2
    3
    4
    5
    6
    7
    8
  2. 实践题:编写一个温度转换程序,将用户输入的华氏温度(double)转换为摄氏温度(double),然后再强制转换为 int 输出(公式:℃ = (℉ - 32) × 5 / 9)。

  3. 思考题:long l = 100; 和 float f = 100L; 都能编译通过(自动类型转换),但 long 是 8 字节而 float 只有 4 字节,为什么小容量的 float 能接收大容量的 long?会有精度损失吗?

# 2.8 包装类

# 2.8.1 包装类介绍

Java 为每种基本类型提供了对应的包装类(Wrapper Class),使基本类型可以作为对象使用。

基本类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

为什么需要包装类?因为集合(如 ArrayList)只能存储对象,不能存储基本类型。

// ArrayList 不能直接存 int
// ArrayList<int> list;  // 编译错误!
ArrayList<Integer> list = new ArrayList<>();  // 用 Integer 包装类
list.add(10);  // 自动装箱:int → Integer
1
2
3
4

# 2.8.2 自动装箱拆箱

Java 5 引入了自动装箱和拆箱:

自动装箱拆箱的原理:自动装箱实际上是编译器在编译时自动插入了 Integer.valueOf() 调用,自动拆箱则插入了 intValue() 调用。这是编译器层面的语法糖,字节码中并不存在自动装箱/拆箱的指令。需要注意的是,频繁的装箱/拆箱会产生大量临时 Integer 对象,影响性能。在循环中应优先使用基本类型。

// 自动装箱:基本类型 → 包装类
Integer a = 10;  // 等价于 Integer a = Integer.valueOf(10);

// 自动拆箱:包装类 → 基本类型
int b = a;       // 等价于 int b = a.intValue();

// 在运算中自动拆箱
Integer x = 10;
Integer y = 20;
int sum = x + y;  // x 和 y 自动拆箱后相加
1
2
3
4
5
6
7
8
9
10

# 2.8.3 包装类缓存

Java 对部分包装类做了缓存优化:

Integer a = 127;
Integer b = 127;
System.out.println(a == b);  // true(缓存范围内,同一个对象)

Integer c = 128;
Integer d = 128;
System.out.println(c == d);  // false(超出缓存范围,不同对象)
System.out.println(c.equals(d));  // true(值相等)
1
2
3
4
5
6
7
8

注意:Integer 缓存了 -128 到 127 的值。比较包装类对象的值应该用 equals(),不要用 ==。

# 2.8.4 常用方法

// 字符串转数值
int i = Integer.parseInt("123");
double d = Double.parseDouble("3.14");
long l = Long.parseLong("123456789");

// 数值转字符串
String s1 = Integer.toString(123);
String s2 = String.valueOf(123);
String s3 = 123 + "";  // 简便写法

// 获取最大值最小值
System.out.println(Integer.MAX_VALUE);  // 2147483647
System.out.println(Integer.MIN_VALUE);  // -2147483648
1
2
3
4
5
6
7
8
9
10
11
12
13

# 2.8.5 综合案例:包装类工具箱

编写一个程序,综合演示包装类的创建方式、自动装箱拆箱、缓存机制、字符串互转以及性能对比。

public class WrapperToolbox {
    public static void main(String[] args) {
        // 1. 创建包装类对象的多种方式
        System.out.println("===== 创建方式对比 =====");
        Integer a1 = Integer.valueOf(100);       // 推荐: valueOf(利用缓存)
        Integer a2 = Integer.valueOf("100");     // 从字符串创建
        int a3 = Integer.parseInt("100");        // 直接解析为基本类型
        System.out.println("valueOf(100): " + a1);
        System.out.println("valueOf(\"100\"): " + a2);
        System.out.println("parseInt(\"100\"): " + a3);

        // 2. 缓存机制深度测试
        System.out.println("\n===== 缓存机制测试 =====");
        System.out.println("--- Integer 缓存 [-128, 127] ---");
        for (int val : new int[]{-128, -1, 0, 1, 127, 128, 256}) {
            Integer x = Integer.valueOf(val);
            Integer y = Integer.valueOf(val);
            System.out.printf("  valueOf(%4d): == %s, equals %s%n",
                    val, x == y, x.equals(y));
        }

        System.out.println("--- Boolean 缓存 ---");
        Boolean t1 = Boolean.valueOf(true);
        Boolean t2 = Boolean.valueOf(true);
        System.out.println("  Boolean.valueOf(true): == " + (t1 == t2));  // true

        System.out.println("--- Character 缓存 [0, 127] ---");
        Character c1 = Character.valueOf('A');  // 65, 在缓存内
        Character c2 = Character.valueOf('A');
        System.out.println("  valueOf('A'): == " + (c1 == c2));  // true

        // 3. 自动装箱拆箱与null安全
        System.out.println("\n===== 自动装箱拆箱与null陷阱 =====");
        Integer num = null;
        try {
            int value = num;  // 自动拆箱:null.intValue() → NPE!
        } catch (NullPointerException e) {
            System.out.println("null自动拆箱抛出NullPointerException!");
        }
        // 安全写法
        int safeValue = (num != null) ? num : 0;
        System.out.println("安全拆箱: " + safeValue);

        // 4. 字符串与数值互转
        System.out.println("\n===== 字符串互转 =====");
        String numStr = "12345";
        int intVal = Integer.parseInt(numStr);
        long longVal = Long.parseLong(numStr);
        double doubleVal = Double.parseDouble("3.14159");
        System.out.println("字符串→int: " + intVal);
        System.out.println("字符串→long: " + longVal);
        System.out.println("字符串→double: " + doubleVal);
        System.out.println("int→字符串: " + Integer.toString(intVal));
        System.out.println("int→二进制: " + Integer.toBinaryString(intVal));
        System.out.println("int→十六进制: " + Integer.toHexString(intVal));

        // 5. 性能对比:基本类型 vs 包装类
        System.out.println("\n===== 性能对比 =====");
        long start, end;
        final int COUNT = 10_000_000;

        // 使用基本类型
        start = System.currentTimeMillis();
        long sum1 = 0;
        for (int i = 0; i < COUNT; i++) {
            sum1 += i;
        }
        end = System.currentTimeMillis();
        System.out.println("基本类型 long 累加: " + (end - start) + "ms, sum=" + sum1);

        // 使用包装类(大量自动装箱拆箱)
        start = System.currentTimeMillis();
        Long sum2 = 0L;
        for (int i = 0; i < COUNT; i++) {
            sum2 += i;  // 每次都拆箱→运算→装箱
        }
        end = System.currentTimeMillis();
        System.out.println("包装类 Long 累加: " + (end - start) + "ms, sum=" + sum2);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

# 2.8.6 训练题

  1. 代码题:请预测输出并解释原因:

    Integer a = new Integer(127);
    Integer b = new Integer(127);
    System.out.println(a == b);
    System.out.println(a.equals(b));
    
    Integer c = Integer.valueOf(127);
    Integer d = Integer.valueOf(127);
    System.out.println(c == d);
    
    1
    2
    3
    4
    5
    6
    7
    8
  2. 实践题:编写一个方法,接受一个 String 参数,将其转换为 int。要求处理以下异常情况:空字符串、非数字字符串、超出 int 范围的数字。

  3. 思考题:自动装箱拆箱虽然方便,但在性能敏感的场景(如大循环中)可能带来问题。请分析以下代码的性能问题并给出优化方案:

    Long sum = 0L;
    for (int i = 0; i < 1000000; i++) {
        sum += i;  // 这里发生了什么?
    }
    
    1
    2
    3
    4

# 2.8.7 类型转换案例

public class Main {
    public static void main(String[] args) {
        // 自动类型转换
        int a = 10;
        double b = a;
        System.out.println("b = " + b);  // 10.0

        // 强制类型转换
        double c = 3.99;
        int d = (int) c;
        System.out.println("d = " + d);  // 3

        // 自动装箱拆箱
        Integer e = 100;    // 自动装箱
        int f = e;           // 自动拆箱
        System.out.println("f = " + f);  // 100

        // 包装类比较
        Integer g = 127;
        Integer h = 127;
        System.out.println("g == h: " + (g == h));         // true
        System.out.println("g.equals(h): " + g.equals(h)); // true

        Integer i = 128;
        Integer j = 128;
        System.out.println("i == j: " + (i == j));         // false
        System.out.println("i.equals(j): " + i.equals(j)); // true
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 2.8.8 键盘数据输入

作用:用于从键盘获取数据

关键类:Scanner

语法: Scanner sc = new Scanner(System.in);

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        // 整型输入
        System.out.print("请输入整数:");
        int a = sc.nextInt();
        System.out.println("a = " + a);

        // 浮点型输入
        System.out.print("请输入小数:");
        double d = sc.nextDouble();
        System.out.println("d = " + d);

        // 字符串输入
        System.out.print("请输入字符串:");
        String str = sc.next();
        System.out.println("str = " + str);

        // 读取一整行
        sc.nextLine();  // 消耗换行符
        System.out.print("请输入一行文字:");
        String line = sc.nextLine();
        System.out.println("line = " + line);

        // 布尔输入
        System.out.print("请输入布尔值(true/false):");
        boolean flag = sc.nextBoolean();
        System.out.println("flag = " + flag);

        sc.close();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

对比 C++:C++ 用 cin >> 变量 读取输入,Java 用 Scanner 类的各种 nextXxx() 方法。

上次更新: 2026/06/10, 11:13:41
基础语法
运算符

← 基础语法 运算符→

最近更新
01
信号崩溃快速排查
06-15
02
CoreDump破案
06-15
03
perf火焰图实战
06-15
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式