云计算百科
云计算领域专业知识百科平台

【Java入门到精通】*基础篇

在这里插入图片描述

Java 入门到精通 (第 1-10 期)

简介:本系列教程从零开始,带你了解 Java 历史、核心特性、环境配置及第一个程序编写。主要基于 Java 8 LTS 版本讲解。


第 1 期:Java 语言发展历史与核心特性介绍

大家好,欢迎来到 Java 入门到精通系列教程的第一期。我是你们的老师,今天咱们从零开始,聊聊 Java 这门语言到底是怎么来的,它有什么牛逼的地方,以及学了 Java 能干啥。

1. Java 的历史

  • 发布时间:1995 年,由 Sun 公司发布。
  • 创始人:James Gosling(詹姆斯·高斯林),被称为“Java 界的祖师爷”。
  • 起源故事:最初是 Sun 公司的内部项目“Green 计划”,旨在开发智能家电的编程语言。随着互联网时代的到来,Java 迅速走红。
  • 命名由来:取自印度尼西亚爪哇岛(Java Island)的英文名,那里盛产咖啡。因此,Java 的 Logo 是一杯冒着热气的咖啡。

2. 版本说明

  • 当前版本:已更新至 Java 21+。
  • LTS 版本:企业中最常用的是长期支持版本(LTS),如 Java 8、Java 11、Java 17 等。
  • 本教程基础:Java 8。因为它最经典、最稳定、企业应用最广。

3. Java 的核心特性

Java 之所以长盛不衰,主要归功于以下五大特性:

  • 面向对象 (OOP)
    • 核心思想:将现实世界抽象为代码中的“对象”(如人、车、猫)。
    • 三大特征:封装、继承、多态(后续章节详细讲解)。
  • 跨平台性 (“一次编写,到处运行”)
    • 原理:依靠 JVM (Java Virtual Machine)。
    • 优势:Windows 上写的代码无需修改,可直接在 Linux/Mac 上运行。C 语言则需针对不同系统重新编译。
  • 简单易学
    • 语法类似 C++,但去除了指针、手动内存管理、多继承等复杂概念。
    • 自动垃圾回收 (GC):无需手动释放内存,降低入门门槛。
  • 安全性
    • 拥有沙箱安全模型等机制,防止恶意代码破坏系统。早期广泛用于浏览器端。
  • 多线程支持
    • 内置多线程支持,允许程序同时执行多个任务,提高效率。
  • 4. Java 的应用领域

    • 后端开发:网站/App 后台服务(主流方向)。
    • 安卓开发:原生 App 开发语言。
    • 大数据:Hadoop、Spark 等框架底层多用 Java/Scala。
    • 游戏开发:例如《我的世界》(Minecraft)。
    • 企业级应用:银行、金融、电商等大型系统。

    第 2 期:跨平台原理与 JVM 虚拟机详解

    上期提到 Java 最牛的特性是跨平台,核心在于 JVM (Java 虚拟机)。

    1. 跨平台原理类比

    • 传统方式 (如 C):像作家写书,需要翻译成各种语言(中文、英文、日文)才能给不同国家的人看。对应代码:Windows 编译的 exe 只能在 Windows 跑,Linux 需重新编译。
    • Java 方式:
    • 先翻译成一种“中间语言”——字节码 (Bytecode)。
    • 每个平台都有一个“翻译官”——JVM,将统一的字节码翻译成该平台能懂的机器码。

    2. Java 执行流程

  • 源代码:.java 文件。
  • 编译:使用 javac 命令,生成 .class 字节码文件(平台无关)。
  • 运行:使用 java 命令,JVM 将字节码翻译为当前平台的机器码执行。
  • 关键点:.class 字节码是平台无关的;JVM 是平台相关的(Windows/Mac/Linux 各有专属 JVM)。

    3. JVM 的主要功能

    JVM 是一个虚拟计算机,包含栈、堆、方法区等内存结构。主要职责包括:

    • 类加载:加载 .class 文件到内存。
    • 字节码验证:检查合法性与安全性。
    • 解释执行:逐条翻译字节码为机器码。
    • 即时编译 (JIT):将热点代码直接编译成本地机器码,提升效率(Java 并非纯解释型语言,效率接近 C++)。
    • 垃圾回收 (GC):自动管理内存。

    第 3 期:JDK、JRE 与 JVM 的关系图解

    初学者常混淆 JDK、JRE、JVM,三者关系如下:

    1. 概念定义

    组件全称定义用途
    JVM Java Virtual Machine Java 虚拟机 运行字节码的核心引擎。
    JRE Java Runtime Environment Java 运行环境 JVM + 核心类库。用于运行 Java 程序,不能开发。
    JDK Java Development Kit Java 开发工具包 JRE + 开发工具 (javac, java, javadoc 等)。用于开发 Java 程序。

    2. 包含关系图

    ┌─────────────────────────────┐
    │ JDK │
    │ ┌───────────────────────┐ │
    │ │ JRE │ │
    │ │ ┌─────────────────┐ │ │
    │ │ │ JVM │ │ │
    │ │ └─────────────────┘ │ │
    │ │ + 核心类库 │ │
    │ └───────────────────────┘ │
    │ + 开发工具(javac等) │
    └─────────────────────────────┘

    • 关系:JDK ⊃ JRE ⊃ JVM

    3. 生活化比喻

    • JVM = 汽车发动机(核心动力,但无法单独驾驶)。
    • JRE = 完整的汽车(有发动机+座椅轮胎,可驾驶/运行,但不能造车/开发)。
    • JDK = 车库+车间(有一辆完整汽车+工具,可造车/开发)。

    4. 安装建议

    • 仅运行程序:装 JRE。
    • 开发 Java 程序:必须装 JDK(内含 JRE,无需单独装 JRE)。
    • JVM:无需单独安装,包含在 JRE/JDK 中。

    第 4 期:下载与安装 JDK 环境(Windows/Mac)

    1. 下载渠道

    • Oracle JDK:官方原版。Java 8+ 商业用途需付费,个人学习免费。
    • OpenJDK:开源免费,企业常用。
    • 其他发行版:Amazon Corretto, 阿里 Dragonwell, 华为 OpenJDK 等。
    • 推荐:初学者使用 Oracle JDK 8 或 OpenJDK 8。务必选择 LTS 版本。

    2. Windows 安装步骤

  • 下载安装包 (.exe)。
  • 双击运行,一路下一步。
  • 路径建议:避免中文和空格。推荐 C:\\Java\\jdk1.8.0_xxx。
  • JRE 可选安装(JDK 已自带)。
  • 3. Mac 安装步骤

  • 下载安装包 (.dmg)。
  • 双击打开,按提示安装。
  • 默认路径:/Library/Java/JavaVirtualMachines/
  • 4. 注意事项

    • 安装路径不要包含中文、空格或特殊字符。
    • 下载对应系统位数的版本(通常选 x64)。
    • 记住安装路径,后续配置环境变量需用。

    第 5 期:配置环境变量(JAVA_HOME 与 Path)

    安装后直接在命令行输入 java 报错,是因为系统找不到命令路径。需配置环境变量。

    1. 关键变量

    • JAVA_HOME:指向 JDK 安装根目录(不含 bin)。
      • 作用:方便其他软件(Tomcat, Maven, IDEA 等)统一读取 JDK 位置。
    • Path:指向 JDK 的 bin 目录。
      • 作用:让系统在任意目录下都能找到 java, javac 等命令。

    2. Windows 配置步骤

  • 新建 JAVA_HOME:
    • 右键“此电脑” → 属性 → 高级系统设置 → 环境变量。
    • 系统变量 → 新建:变量名 JAVA_HOME,变量值 C:\\Java\\jdk1.8.0_202 (示例路径)。
  • 编辑 Path:
    • 系统变量 → 找到 Path → 编辑。
    • 新建条目:%JAVA_HOME%\\bin。
    • 重要:将此条目移动到列表最上方,确保优先使用自己安装的 JDK。
  • 保存退出。
  • 3. Mac 配置步骤

  • 打开终端,编辑配置文件 (~/.zshrc 或 ~/.bash_profile)。
  • 添加以下内容:export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home
    export PATH=$JAVA_HOME/bin:$PATH

  • 使配置生效:source ~/.zshrc

  • 第 6 期:验证安装与命令行常用指令

    1. 验证安装

    打开命令行 (Win: cmd, Mac: Terminal),输入以下命令:

    # 查看 Java 版本
    java -version

    # 查看编译器版本
    javac -version

    • 成功标志:显示版本号 (如 1.8.0_202)。
    • 失败处理:若提示“不是内部或外部命令”,请检查环境变量配置。

    2. 常用命令行指令

    作用WindowsMac / Linux
    查看当前目录 cd (无参) pwd
    切换目录 cd 路径 cd 路径
    返回上一级 cd .. cd ..
    列出文件 dir ls
    创建文件夹 mkdir 名 mkdir 名
    删除文件 del 文件名 rm 文件名
    清屏 cls clear
    • 技巧:使用 Tab 键可进行文件名/目录名自动补全。
    • 路径概念:
      • 绝对路径:从根目录开始的完整路径 (如 C:\\Java\\…)。
      • 相对路径:相对于当前目录的路径 (如 ./src)。

    第 7 期:编写第一个 HelloWorld 程序

    1. 创建文件

    • 新建文本文件,命名为 HelloWorld.java。
    • 注意:必须显示文件扩展名。Windows 需在“查看”中勾选“文件扩展名”。
    • 严禁:文件名为 HelloWorld.java.txt。

    2. 编写代码

    使用记事本或编辑器打开,输入:

    public class HelloWorld {
    public static void main(String[] args) {
    System.out.println("Hello World!");
    }
    }

    3. 关键规范

  • 文件名与类名一致:public class 后的名称必须与文件名完全匹配(区分大小写)。
  • 符号规范:所有括号、分号、引号必须为英文半角。
  • 大小写敏感:System != system, String != string。
  • 语句结束:每行语句必须以分号 ; 结尾。

  • 第 8 期:编译与运行 Java 程序 (javac 与 java)

    1. 操作流程

  • 切换目录:进入 .java 文件所在目录。cd D:\\code\\java_project
  • 编译:使用 javac 生成字节码。javac HelloWorld.java
    • 成功:无输出,目录下生成 HelloWorld.class。
    • 失败:根据错误信息修正拼写、符号或文件名问题。
  • 运行:使用 java 命令执行类名。java HelloWorld
    • 注意:只写类名,不要加 .java 或 .class。
    • 结果:控制台输出 Hello World!。
  • 2. 常见错误

    • java HelloWorld.class:报错,因为 JVM 寻找的是类名而非文件名。
    • 中文乱码:编译时指定编码 javac -encoding UTF-8 HelloWorld.java。

    第 9 期:HelloWorld 程序逐行代码剖析

    public class HelloWorld {
    public static void main(String[] args) {
    System.out.println("Hello World!");
    }
    }

    1. 第一行:类的定义

    public class HelloWorld {

    • public:访问修饰符,表示公开可见。
    • class:关键字,定义一个类。
    • HelloWorld:类名。
    • {:类体开始。

    2. 第二行:主方法 (入口)

    public static void main(String[] args) {

    • public:公共权限,供 JVM 调用。
    • static:静态方法,无需实例化对象即可调用。
    • void:无返回值。
    • main:方法名,固定写法,JVM 识别的入口。
    • (String[] args):参数列表,接收命令行字符串数组(初学者暂忽略)。

    3. 第三行:输出语句

    System.out.println("Hello World!");

    • System:系统类。
    • out:标准输出流对象。
    • println():打印并换行方法。
    • "Hello World!":字符串常量。
    • ;:语句结束符。

    4. 总结

    • Java 基本单位是类。
    • 程序入口是固定的 main 方法。
    • 输出使用 System.out.println。

    第 10 期:开发工具 IDEA 的安装与基础配置

    为了提升开发效率,建议使用集成开发环境 (IDE),首选 IntelliJ IDEA。

    1. 版本选择

    • Community (社区版):免费,支持 Java SE,适合初学者。
    • Ultimate (旗舰版):收费,支持 Web/EE 等企业级开发。

    2. 安装步骤

  • 官网下载 Community 版安装包。
  • 安装路径避免中文/空格。
  • 推荐勾选选项:
    • Create Desktop Shortcut (桌面快捷方式)
    • Update PATH Variable (命令行可用 idea 命令)
    • Update Context Menu (右键菜单集成)
    • .java 关联 (默认用 IDEA 打开)
  • 3. 首次启动与界面

    • 新建项目 (New Project):选择 Java 语言,指定 JDK 8。
    • 界面区域:
      • 左侧:项目结构。
      • 中间:代码编辑区。
      • 下方:控制台/终端。
      • 顶部:菜单栏/工具栏。

    4. 推荐基础配置 (File → Settings)

  • 字体大小:Editor → Font,Size 设为 16-18。
  • 自动导包:Editor → General → Auto Import,勾选相关选项。
  • 滚轮缩放字体:Editor → General,勾选 Change font size with Ctrl+Mouse Wheel。
  • 显示行号:Editor → General → Appearance → Show line numbers。
  • 文件编码:Editor → File Encodings,全局和项目编码均设为 UTF-8 (防止中文乱码)。


  • Java 入门到精通 (第 11-20 期)

    简介:本阶段从 IDE 实操入手,深入讲解 Java 基础语法核心概念,包括关键字、标识符、注释、常量、基本数据类型(整数、浮点、字符、布尔)。


    第 11 期:IDEA 中创建项目与运行程序

    1. 创建新项目

    打开 IntelliJ IDEA,点击 New Project,配置如下:

    • Name:项目名称,如 JavaStudy。
    • Location:项目路径,避免中文和空格。
    • Language:选择 Java。
    • JDK:选择已安装的 JDK 8(若未检测到需手动添加)。
    • Build system:选择 IntelliJ(初学者暂不使用 Maven/Gradle)。

    2. 创建类

    • 在左侧项目结构的 src 文件夹上右键 → New → Java Class。
    • 输入类名(如 HelloWorld),回车。
    • IDEA 会自动生成类结构:public class HelloWorld {
      }

    3. 编写代码与快捷键

    • 生成 main 方法:输入 psvm 然后按 Tab 键。public static void main(String[] args) {
      }

    • 生成输出语句:在 main 方法中输入 sout 然后按 Tab 键。System.out.println();
    • 完整示例:public class HelloWorld {
      public static void main(String[] args) {
      System.out.println("Hello IDEA!");
      }
      }

    4. 运行程序

    有以下几种方式运行:

  • 点击 main 方法左侧的绿色小三角。
  • 右键代码编辑区 → Run ‘HelloWorld.main()’。
  • 快捷键:Ctrl+Shift+F10 (Windows) / Control+Shift+R (Mac)。
  • 点击右上角绿色播放按钮。
    • 结果查看:下方控制台输出 Hello IDEA! 及 Process finished with exit code 0(0 表示正常退出)。
    • 优势:IDEA 自动完成编译和运行,无需手动敲命令。

    5. 常用操作

    • 新建包:src 右键 → New → Package(用于分类管理代码)。
    • 重命名:选中文件 → Shift+F6(IDEA 会自动更新所有引用)。
    • 代码提示:输入部分字母后,IDEA 会自动补全,善用此功能提高效率。

    第 12 期:IDEA 常用快捷键与调试技巧入门

    熟练掌握快捷键可大幅提升开发效率。

    1. 核心快捷键速查表

    类别Windows 快捷键Mac 快捷键作用
    生成代码 psvm + Tab psvm + Tab 生成 main 方法
    sout + Tab sout + Tab 生成 System.out.println()
    编辑 Ctrl + D Cmd + D 复制当前行到下一行
    Ctrl + Y Cmd + Backspace 删除当前行
    Ctrl + / Cmd + / 单行注释/取消注释
    Ctrl + Shift + / Cmd + Shift + / 多行注释/取消注释
    Ctrl + Alt + L Option + Cmd + L 格式化代码(自动对齐)
    Alt + Enter Option + Enter 万能修复键(导包、修错、提取方法等)
    Ctrl + Alt + V Option + Cmd + V 自动生成变量
    查找 Ctrl + F Cmd + F 当前文件查找
    Ctrl + Shift + F Cmd + Shift + F 全局查找
    双击 Shift 双击 Shift 万能搜索(搜类、文件、设置等)
    运行/调试 Ctrl + Shift + F10 Control + R 运行当前程序
    Ctrl + Shift + F9 Control + D 调试运行当前程序
    F8 F8 单步执行(不进入方法内部)
    F7 F7 单步执行(进入方法内部)
    F9 F9 继续执行(至下一个断点)
    Ctrl + F2 Cmd + F2 停止程序

    2. 调试 (Debug) 技巧入门

    调试是定位 Bug 的核心手段,让程序一步步执行并观察变量值。

  • 设置断点:在代码行号左侧点击,出现红色圆点。
  • 启动调试:点击 Debug 图标(虫子形状)或按调试快捷键。
  • 暂停观察:程序运行至断点处暂停,查看下方 Debug 面板中的变量值。
  • 逐步执行:
    • F7:Step Into(进入方法)。
    • F8:Step Over(跳过方法,不进入)。
    • F9:Resume Program(继续运行直到下一个断点)。
  • 结束调试:找到问题后,修改代码并重新运行。

  • 第 13 期:关键字与保留字的区别

    1. 关键字 (Keyword)

    • 定义:Java 语言中被赋予特殊含义的单词。
    • 特点:
      • 全部为小写。
      • 具有特定用途(如定义类、变量、流程控制等)。
      • 在 IDEA 中通常显示为蓝色或紫色高亮。
      • 不能用作类名、方法名、变量名。
    • 常见分类:
      • 修饰符:public, private, protected, static, final, abstract
      • 流程控制:if, else, switch, case, while, for, break, continue, return
      • 数据类型:int, long, double, char, boolean, true, false, null
      • 面向对象:class, interface, extends, implements, new, this, super
      • 异常处理:try, catch, finally, throw, throws
      • 其他:package, import, synchronized, volatile, enum

    2. 保留字 (Reserved Word)

    • 定义:Java 目前未使用,但预留供未来版本可能使用的关键字。
    • 数量:仅两个 —— const 和 goto。
    • 原因:
      • const:Java 使用 final 定义常量,故保留 const。
      • goto:Java 认为 goto 容易导致代码逻辑混乱,故废弃,但仍保留该词禁止使用。

    3. 总结

    • 共同点:都不能作为标识符(名字)使用。
    • 判断方法:在 IDEA 中输入,若变色则为关键字/保留字;若为黑色则不是。
    • 注意:true, false, null 虽常被视为字面量,但在标识符规则中同样不可用。

    第 14 期:标识符的命名规则与规范

    标识符是给类、方法、变量等起的名字。

    1. 命名规则(必须遵守,否则报错)

  • 组成字符:字母、数字、下划线 _、美元符号 $。
  • 开头限制:不能以数字开头。
  • 关键字限制:不能是关键字或保留字。
  • 大小写敏感:Age 和 age 是不同的标识符。
  • 长度:理论上无限制。
  • 示例:

    • ✅ age, studentName, _hello, $money, abc123
    • ❌ 123abc (数字开头), class (关键字), my-name (含减号)
    • ⚠️ 我的名字 (合法但不推荐,易导致编码问题和可读性差)

    2. 命名规范(建议遵守,体现专业性)

    类型规范名称规则示例
    类名/接口名 大驼峰 (UpperCamelCase) 每个单词首字母大写 HelloWorld, UserService
    方法名/变量名 小驼峰 (lowerCamelCase) 第一个单词小写,后续单词首字母大写 main, userName, getInfo
    常量名 全大写 全部大写,单词间用下划线分隔 MAX_SIZE, PI, DEFAULT_VALUE
    包名 全小写 全部小写,用点分隔层级 com.example.demo, java.util

    3. 核心原则:见名知意

    • 好例子:age, studentName, calculateSum
    • 坏例子:a, b, test, helloworld (类名未大写)
    • 理由:代码是给人看的,清晰的名字能像文章一样顺畅阅读,减少维护成本。

    第 15 期:注释的三种方式

    注释是写给程序员看的说明,编译器会忽略。

    1. 单行注释

    • 语法:// 注释内容
    • 用法:解释单行代码或行尾补充说明。
    • 快捷键:Ctrl + / (Win) / Cmd + / (Mac)

    // 这是一个单行注释
    int age = 18; // 定义年龄变量

    2. 多行注释

    • 语法:/* 注释内容 */
    • 用法:注释大块代码或多行说明。注意:不能嵌套使用。
    • 快捷键:Ctrl + Shift + / (Win) / Cmd + Shift + / (Mac)

    /*
    这是一个多行注释
    可以包含多行文字
    */

    3. 文档注释 (Javadoc)

    • 语法:/** 注释内容 */
    • 用法:专门用于生成 API 文档,写在类、方法、字段上方。
    • 常用标签:
      • @author:作者
      • @version:版本号
      • @param:参数说明
      • @return:返回值说明
      • @deprecated:已废弃

    /**
    * 计算圆的面积
    * @param radius 半径
    * @return 面积
    */

    public double calculateArea(double radius) { ... }

    4. 注释原则

    • 要写:类和方法的文档注释、复杂业务逻辑的解释、特殊处理的“坑”。
    • 不要写:废话注释(如 int a = 1; // a等于1)、过时注释(代码改了注释没改比没注释更坑)。

    第 16 期:常量的定义与 final 关键字

    1. 常量分类

    • 字面常量:直接写出的固定值,如 123, "Hello", true, null。
    • 自定义常量:使用 final 关键字修饰的变量,值一旦确定不可更改。

    2. final 关键字

    • 修饰变量:变为常量,初始化后不可重新赋值。
    • 修饰方法:不能被重写(Override)。
    • 修饰类:不能被继承(Extend)。

    3. 定义与使用

    // 语法:final 数据类型 常量名 = 值;
    final double PI = 3.1415926;
    final int MAX_SIZE = 100;

    // 错误示范
    final int age = 18;
    age = 20; // 编译报错!Cannot assign a value to final variable 'age'

    4. 使用场景

  • 固定不变的值:如圆周率 PI。
  • 替代魔法值:提高可读性。
    • Bad: if (age > 18)
    • Good: final int ADULT_AGE = 18; if (age > ADULT_AGE)
  • 便于维护:多处引用的值,只需修改常量定义一处即可。
  • 5. 注意事项

    • 局部常量必须在定义时初始化。
    • 常量名规范:全大写 + 下划线。

    第 17 期:基本数据类型分类(8 大基本类型)

    Java 数据类型分为基本类型和引用类型。本期重点讲解 8 大基本数据类型,口诀:“四类八种”。

    1. 整数类型 (4 种)

    类型字节范围默认值备注
    byte 1 -128 ~ 127 0 极少用,节省空间场景
    short 2 -32768 ~ 32767 0 极少用
    int 4 ±21亿 0 最常用
    long 8 ±900亿亿 0L 大数、时间戳
    • 注意:整数默认类型为 int。定义 long 需加后缀 L。

    2. 浮点类型 (2 种)

    类型字节精度默认值备注
    float 4 6-7位有效数字 0.0f 需加后缀 f
    double 8 15-16位有效数字 0.0 最常用
    • 注意:小数默认类型为 double。定义 float 需加后缀 f。
    • 警告:浮点数运算存在精度误差,严禁用于金额计算(需用 BigDecimal)。

    3. 字符类型 (1 种)

    • char: 2 字节,Unicode 编码,取值 0~65535。
    • 示例:'a', '中', '\\n'

    4. 布尔类型 (1 种)

    • boolean: 1 字节(规范未严格规定),只有 true 或 false。
    • 用于条件判断。

    第 18 期:整数类型详解 (byte, short, int, long)

    1. 各类型详解

    • byte: 最小单位,常用于网络传输、文件读写底层数据。
    • short: 介于 byte 和 int 之间,现代开发中很少使用。
    • int: 主力军。绝大多数计数、索引、ID 都使用 int。
    • long: 当数值超过 int 范围时使用。
      • 典型场景:System.currentTimeMillis() 返回的时间戳。
      • 写法:long num = 10000000000L; (务必加 L,防止溢出)。

    2. 进制表示

    Java 支持多种进制的字面量表示,打印时默认转为十进制:

    • 十进制:123
    • 二进制:0b1010 (以 0b 开头)
    • 八进制:012 (以 0 开头)
    • 十六进制:0xA (以 0x 开头)

    3. 数字可视化增强 (Java 7+)

    可以在数字中间加下划线 _ 提高可读性,编译器会自动忽略:

    int million = 1_000_000; // 100万
    long billion = 1_000_000_000L; // 10亿

    4. 经验总结

  • 日常开发首选 int。
  • 超大数选 long,记得加 L。
  • 注意溢出问题,确保数据在类型范围内。

  • 第 19 期:浮点类型详解 (float vs double)

    1. 核心区别

    • precision (精度): double > float。
    • memory (内存): double 占用更多内存。
    • 默认类型: 代码中写的小数默认是 double。

    2. 定义语法

    float f = 3.14f; // 必须加 f/F
    double d = 3.14; // 默认就是 double,d/D 可选
    double d2 = 3.14d;

    3. 精度陷阱 (重要!)

    计算机使用二进制存储小数,部分十进制小数无法精确表示(类似 1/3 = 0.333…)。

    System.out.println(0.1 + 0.2);
    // 输出: 0.30000000000000004

    • 结论:涉及金钱、精确计算的场景,绝对禁止使用 float/double,必须使用 java.math.BigDecimal。

    4. 特殊值

    • Infinity: 正无穷 (1.0 / 0)
    • -Infinity: 负无穷 (-1.0 / 0)
    • NaN: 非数字 (0.0 / 0.0)。注意:NaN == NaN 结果为 false,判断需用 Double.isNaN()。

    5. 科学计数法

    double e2 = 3.14e2; // 314.0
    double eNeg3 = 3.14e-3; // 0.00314


    第 20 期:字符类型 char 与 Unicode 编码

    1. char 基础

    • 占位:2 字节 (16 bit),范围 0~65535。
    • 语法:单引号 ' ',只能存一个字符。char c = 'a';
      char c2 = '中';
      // char c3 = "ab"; // 错误,这是字符串

    2. char 的本质:数字

    char 在底层存储的是字符对应的 Unicode 编码值。

    • 隐式转换:char 参与算术运算时,自动提升为 int。char c = 'a'; // ASCII 97
      System.out.println(c + 1); // 输出 98

    • 强制转换:可以将数字赋给 char,显示对应字符。char c = 97;
      System.out.println(c); // 输出 a

    3. 关键编码值 (ASCII)

    记住以下常用字符的编码,有助于理解字符运算:

    • '0' = 48
    • 'A' = 65
    • 'a' = 97
    • 大小写差值:32 ('a' – 'A' = 32)

    4. 转义字符 ($

    用于表示特殊控制字符:

    转义符含义示例
    \\n 换行 "Line1\\nLine2"
    \\t 制表符 "Name\\tAge"
    \\\\ 反斜杠 "C:\\\\Path"
    \\' 单引号 char c = '\\'';
    \\" 双引号 String s = "\\"Hello\\"";
    \\uXXXX Unicode 字符 '\\u4e2d' (中)

    5. 常见应用

    • 大小写转换:利用 ASCII 差值 32。char upper = (char)(c 32); // 小转大
      char lower = (char)(c + 32); // 大转小

    • 类型判断:通过范围判断字符类型。if (c >= '0' && c <= '9') { /* 数字 */ }
      else if (c >= 'a' && c <= 'z') { /* 小写字母 */ }



    Java 入门到精通 (第 21-30 期)

    简介:本阶段深入讲解基本数据类型的细节、变量管理、类型转换、字符串操作、Scanner 输入处理以及格式化输出,并通过综合案例巩固基础语法。


    第 21 期:布尔类型 boolean 的特殊性

    1. 基本用法

    boolean 类型只有两个值:true 和 false。

    • 注意:必须小写,它们是关键字,不能作为标识符。
    • 示例:boolean flag = true;
      System.out.println(flag); // 输出 true

    2. 特殊性

    与其他基本类型相比,boolean 有以下特点:

  • 取值唯一:仅 true / false。
  • 不可转换:不能与整数、浮点数等相互转换。(不同于 C 语言中 0 为假、非 0 为真)。
    • ❌ int a = true; (编译报错)
    • ❌ boolean b = 1; (编译报错)
  • 内存占用未明确规定:规范未规定具体字节数,通常单独变量占 4 字节(类似 int),数组中占 1 字节。
  • 3. 使用场景

    • 条件判断:if, while, for 的条件表达式必须是 boolean 类型。
    • 方法返回值:用于返回逻辑判断结果(如 isEven(), isValid())。
    • 标志位:记录状态(如 isFinished, isVisible)。

    4. 命名建议

    变量名建议以 is, has, can, should 开头,见名知意。

    • ✅ isAdult, hasNext, canRun

    第 22 期:变量的声明与初始化

    1. 概念

    变量是内存中的一块存储空间,具有类型、名字和值。

    2. 语法步骤

  • 声明:告诉编译器变量的类型和名字。int age;
    double salary;

  • 初始化(赋值):给变量赋予初始值。age = 18;
  • 声明并初始化(推荐):int age = 18;
  • 3. 注意事项

  • 先声明后使用:未声明的变量无法访问。
  • 局部变量必须先初始化:在方法内定义的变量,若未赋值,Java 不允许读取(因为栈内存中的值是随机的垃圾值)。
  • 作用域内不可重名:同一作用域内不能有同名变量。
  • 强类型语言:变量类型确定后不可更改(如 int 只能存整数)。

  • 第 23 期:变量的作用域与生命周期

    1. 作用域 (Scope)

    变量能起作用的范围,即代码中可以访问该变量的区域。

    • 规则:
      • 变量在其所在的大括号 {} 内有效。
      • 内部可以访问外部变量。
      • 外部不能访问内部变量。
      • 不同作用域可以有同名变量(但不建议,易混淆)。

    public class ScopeTest {
    public static void main(String[] args) {
    int a = 10;
    if (a > 5) {
    int b = 20;
    System.out.println(a); // 合法,访问外部变量
    System.out.println(b); // 合法,访问内部变量
    }
    // System.out.println(b); // 报错!b 已超出作用域
    }
    }

    2. 生命周期 (Life Cycle)

    变量从创建到销毁的时间段。

    • 局部变量:
      • 创建:执行到声明行时分配内存。
      • 销毁:离开作用域(如方法结束)时内存被回收。
      • 每次调用方法都会重新创建新的局部变量。

    第 24 期:自动类型转换(隐式转换)

    1. 定义

    当小范围类型的数据赋值给大范围类型的变量时,Java 自动完成转换,无需人工干预。

    2. 转换顺序(由小到大)

    byte → short → int → long → float → double

    char

    • 注意:
      • boolean 不参与任何类型转换。
      • float 虽然只有 4 字节,但表示范围比 long (8 字节) 大,所以 long 可自动转为 float。
      • char 可自动转为 int 及以上类型。

    3. 表达式中的类型提升

    • 规则 1:byte, short, char 参与运算时,自动提升为 int。byte a = 10;
      byte b = 20;
      // byte c = a + b; // 报错!结果是 int
      int c = a + b; // 正确

    • 规则 2:混合运算中,整个表达式提升为精度/范围最大的类型。int a = 10;
      double b = 3.14;
      double c = a + b; // a 自动转为 double,结果为 double


    第 25 期:强制类型转换(显式转换)与精度丢失

    1. 定义

    将大范围类型转换为小范围类型时,必须手动指定,称为强制类型转换。

    • 语法:(目标类型) 值

    int a = 10;
    byte b = (byte) a; // 强制转换

    2. 风险:精度丢失与溢出

    • 数值溢出:如果值超出目标类型范围,会发生截断,导致结果错误。int c = 200;
      byte d = (byte) c; // 输出 -56 (溢出)

    • 小数截断:浮点转整数时,直接丢弃小数部分,不是四舍五入。double d = 3.99;
      int i = (int) d; // 结果为 3

    3. 特殊场景

    • byte/short 运算:结果默认为 int,赋值回原类型需强转。byte c = (byte)(a + b); // 必须加括号整体强转
    • 常量优化:如果赋值的是常量且值在范围内,编译器会自动处理,无需强转。byte b = 100; // 合法,100 在 byte 范围内
      int a = 100;
      // byte b2 = a; // 报错,变量 a 的值不确定


    第 26 期:字符串 String 的基础入门

    1. 基本概念

    • String 是引用类型(类),不是基本类型。
    • 用双引号 "" 表示。
    • 不可变性:字符串对象一旦创建,内容不可改变。修改操作(如 toUpperCase)返回的是新字符串对象。

    2. 定义方式

    String s1 = "Hello"; // 推荐:直接量
    String s2 = new String("Hello"); // 较少用

    3. 常用方法

    方法说明示例
    length() 获取长度 "abc".length() -> 3
    charAt(index) 获取指定位置字符 "abc".charAt(0) -> ‘a’
    equals(obj) 比较内容是否相等 "abc".equals("abc") -> true
    toUpperCase() 转大写 "abc".toUpperCase() -> “ABC”
    toLowerCase() 转小写 "ABC".toLowerCase() -> “abc”
    contains(s) 是否包含子串 "hello".contains("ell") -> true
    trim() 去除首尾空格 " ab ".trim() -> “ab”

    4. 重要提醒

    • 比较内容:务必使用 .equals(),不要使用 ==(== 比较的是内存地址)。
    • 拼接:+ 号可用于拼接,其他类型会自动转为字符串。
      • 注意运算顺序:1 + 2 + "abc" -> "3abc";"abc" + 1 + 2 -> "abc12"。

    第 27 期:Scanner 类实现键盘录入

    1. 使用步骤

  • 导包:import java.util.Scanner;
  • 创建对象:Scanner sc = new Scanner(System.in);
  • 调用方法:根据数据类型选择方法。
  • 2. 常用读取方法

    • nextInt(): 读取整数。
    • nextDouble(): 读取小数。
    • nextBoolean(): 读取布尔值 (true/false)。
    • next(): 读取一个单词(遇到空格停止)。
    • nextLine(): 读取一整行(遇到回车停止)。

    3. 常见坑:nextInt 与 nextLine 混用

    • 问题:nextInt() 只读取数字,不读取末尾的换行符 \\n。紧接着调用 nextLine() 会读到空字符串。
    • 解决方案:
    • 在 nextInt() 后额外调用一次 sc.nextLine() 消耗掉换行符。
    • 全部使用 nextLine() 读取,再通过 Integer.parseInt() 转换。

    第 28 期:Scanner 综合练习

    案例 1:用户信息录入

    结合 nextLine, nextInt, nextDouble 录入姓名、年龄、身高。

    import java.util.Scanner;

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

    System.out.print("请输入姓名:");
    String name = sc.nextLine(); // 姓名可能含空格,用 nextLine

    System.out.print("请输入年龄:");
    int age = sc.nextInt(); // 年龄是整数

    System.out.print("请输入身高:");
    double height = sc.nextDouble(); // 身高是小数

    System.out.println("信息:" + name + ", " + age + "岁, " + height + "米");
    sc.close();
    }
    }

    案例 2:简易加法计算器

    import java.util.Scanner;

    public class SimpleCalculator {
    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    System.out.print("请输入第一个数:");
    int num1 = sc.nextInt();
    System.out.print("请输入第二个数:");
    int num2 = sc.nextInt();
    System.out.println("结果:" + (num1 + num2));
    sc.close();
    }
    }


    第 29 期:System.out.printf 格式化输出

    1. 基本语法

    System.out.printf("格式字符串", 参数1, 参数2...);

    2. 常用占位符

    占位符类型说明
    %d 整数 十进制
    %f 浮点 默认 6 位小数
    %s 字符串
    %c 字符
    %b 布尔
    %x 整数 十六进制
    %n 换行
    %% 百分号本身

    3. 高级控制

    • 保留小数:%.2f (保留两位,四舍五入)。
    • 宽度对齐:
      • %10d: 右对齐,宽度 10。
      • %-10d: 左对齐,宽度 10。
    • 补零:%04d (不足 4 位前面补 0,如 0005)。
    • 千分位:%,d (如 1,234,567)。

    4. 字符串格式化

    String.format("格式", 参数) 返回格式化后的字符串,不直接打印。


    第 30 期:基础语法综合练习:简易计算器

    需求

    实现支持 +, -, *, / 的计算器,要求:

  • 接收两个操作数(double)。
  • 接收运算符(String)。
  • 计算并输出结果(保留两位小数)。
  • 处理除数为 0 和无效运算符的情况。
  • 完整代码

    import java.util.Scanner;

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

    System.out.println("=== 简易计算器 ===");
    System.out.print("请输入第一个数:");
    double num1 = sc.nextDouble();

    System.out.print("请输入运算符 (+ – * /):");
    String op = sc.next();

    System.out.print("请输入第二个数:");
    double num2 = sc.nextDouble();

    double result = 0;
    boolean valid = true;

    // 判断运算符
    if (op.equals("+")) {
    result = num1 + num2;
    } else if (op.equals("-")) {
    result = num1 num2;
    } else if (op.equals("*")) {
    result = num1 * num2;
    } else if (op.equals("/")) {
    if (num2 == 0) {
    System.out.println("错误:除数不能为 0!");
    valid = false;
    } else {
    result = num1 / num2;
    }
    } else {
    System.out.println("错误:无效的运算符!");
    valid = false;
    }

    // 输出结果
    if (valid) {
    System.out.printf("%.2f %s %.2f = %.2f%n", num1, op, num2, result);
    }

    sc.close();
    }
    }

    知识点回顾

    • Scanner: 数据输入。
    • String: equals() 比较字符串。
    • Math: 算术运算。
    • Control Flow: if-else 分支判断(虽本期未详细讲语法,但已在代码中使用)。
    • Formatting: printf 格式化输出。


    Java 入门到精通 (第 31-40 期)

    简介:本阶段深入讲解 Java 运算符体系,包括算术、字符串拼接、自增自减、赋值、关系、逻辑(含短路)、位运算、位移以及三元运算符。重点解析易错点和面试考点。


    第 31 期:算术运算符 (+, -, *, /, %)

    1. 基本算术运算符

    运算符含义示例结果
    + 加法 5 + 3 8
    减法 5 – 3 2
    * 乘法 5 * 3 15
    / 除法 5 / 3 1 (整数截断)
    % 取模(余数) 5 % 3 2

    2. 整数除法陷阱

    • 规则:两个整数相除,结果仍为整数,直接截断小数部分(非四舍五入)。System.out.println(5 / 3); // 输出 1
    • 获取小数结果:确保至少有一个操作数是浮点数。System.out.println(5.0 / 3); // 1.666…
      System.out.println((double)5 / 3); // 1.666…

    3. 取模运算 (%) 的应用

    • 判断奇偶:num % 2 == 0 为偶数。
    • 获取低位:num % 10 获取个位数。
    • 范围控制:生成随机数时常用 random() % n。

    4. 其他特性

    • 正负号:+5, -3 为一元运算符。
    • 字符运算:char 参与运算时自动转为 ASCII/Unicode 码值。char c = 'a';
      System.out.println(c + 1); // 98 ('b'的编码)

    • 字符串拼接:+ 号若有一边是字符串,则执行拼接而非加法。

    第 32 期:字符串拼接与 + 号重载

    1. 运算符重载

    Java 中只有 + 号支持重载:

    • 两边都是数字 → 加法。
    • 有一边是字符串 → 拼接。

    2. 拼接顺序与括号

    + 号从左往右计算,类型决定行为。

    System.out.println(1 + 2 + "abc"); // "3abc" (先算 1+2=3,再拼)
    System.out.println("abc" + 1 + 2); // "abc12" (先拼 "abc"+1="abc1",再拼)

    // 使用括号改变优先级
    System.out.println("结果:" + (1 + 2)); // "结果:3"

    3. 底层原理

    • 常量拼接:编译器优化为直接拼接 "HelloWorld"。
    • 变量拼接:底层使用 StringBuilder.append()。
      • 注意:在循环中大量使用 + 拼接字符串会频繁创建对象,导致性能下降。建议改用 StringBuilder。

    4. 特殊值处理

    • 空字符串 "":拼接后无变化。
    • null:拼接时会转换为字符串 "null",不会报空指针异常。String s = null;
      System.out.println(s + "abc"); // 输出 "nullabc"


    第 33 期:自增自减运算符 (++ / –)

    1. 前缀式 vs 后缀式

    • 前缀式 (++a, –a):先变后用。先让变量加减 1,再使用新值。
    • 后缀式 (a++, a–):先用后变。先使用原值,再让变量加减 1。

    2. 示例对比

    int a = 10;
    int b = a++; // b=10, a=11 (后缀:先用10赋值给b,a再变11)

    int c = 10;
    int d = ++c; // d=11, c=11 (前缀:c先变11,再用11赋值给d)

    3. 注意事项

    • 单独使用无区别:a++; 和 ++a; 效果相同。
    • 仅作用于变量:5++ 或 (a+b)++ 非法。
    • 面试题陷阱:int a = 10;
      a = a++;
      System.out.println(a); // 输出 10
      // 解析:后缀式先用原值10,a变为11,最后把原值10赋回给a,所以a还是10。

    • 开发建议:避免在复杂表达式中混用自增自减,保持代码可读性。

    第 34 期:赋值与扩展赋值运算符

    1. 基本赋值

    = :将右侧值赋给左侧变量。左侧必须是变量。

    2. 扩展赋值运算符

    包括 +=, -=, *=, /=, %= 等。

    int a = 10;
    a += 5; // 等价于 a = a + 5;

    3. 隐藏的类型转换 (重要!)

    扩展赋值运算符会自动进行强制类型转换。

    byte b = 10;
    // b = b + 1; // 报错!b+1结果是int,不能直接赋给byte
    b += 1; // 正确!等价于 b = (byte)(b + 1)

    • 风险:如果结果超出目标类型范围,会发生溢出,但编译器不会报错。byte b = 127;
      b += 1; // 结果为 -128 (溢出)


    第 35 期:关系运算符

    1. 常用符号

    == (等于), != (不等于), > (大于), < (小于), >= (大于等于), <= (小于等于)。

    • 结果:均为 boolean 类型。

    2. 常见错误:= vs ==

    • = 是赋值。
    • == 是比较。
    • 隐蔽 Bug:boolean flag = false;
      if (flag = true) { ... } // 这是赋值,永远成立!
      // 建议写法:if (true == flag) { … } // 写反了编译报错,便于发现

    3. 字符串比较

    • 严禁使用 == 比较内容:== 比较的是内存地址。
    • 必须使用 .equals():String s1 = new String("hello");
      String s2 = new String("hello");
      System.out.println(s1 == s2); // false (地址不同)
      System.out.println(s1.equals(s2)); // true (内容相同)


    第 36 期:逻辑运算符 (&, |, ^, !)

    1. 基础逻辑运算

    运算符名称规则口诀
    & 全真才真 有假则假
    ` ` 有真则真
    ^ 异或 不同为真 同假异真
    ! 取反 真假互换

    2. 优先级

    ! > & > ^ > |

    3. 双重身份

    & 和 | 既可用于逻辑运算(操作数为 boolean),也可用于位运算(操作数为整数)。


    第 37 期:短路逻辑运算符 (&&, ||)

    1. 短路机制

    • && (短路与):若左边为 false,右边不执行,直接返回 false。
    • || (短路或):若左边为 true,右边不执行,直接返回 true。
    • 对比 & 和 |:无论左边结果如何,右边一定执行。

    2. 为什么用短路?

  • 效率:避免不必要的计算。
  • 安全 (防 NPE):常用于判空。String s = null;
    // if (s != null && s.length() > 0) // 安全:s!=null为false,跳过length()调用
    // if (s != null & s.length() > 0) // 危险:右边仍执行,抛出 NullPointerException

  • 3. 开发规范

    实际业务开发中,逻辑判断几乎全部使用 && 和 ||。& 和 | 主要用于位运算。


    第 38 期:位运算符基础 (&, |, ^, ~)

    1. 按位与 &

    • 规则:对应位都为 1 则为 1。
    • 应用:判断奇偶 (num & 1)、清零、提取指定位。

    2. 按位或 |

    • 规则:对应位有一个为 1 则为 1。
    • 应用:设置特定位为 1。

    3. 按位异或 ^

    • 规则:对应位不同则为 1。
    • 特性:
      • a ^ a = 0
      • a ^ 0 = a
      • 满足交换律和结合律。
    • 经典应用:无需临时变量交换两个整数。a = a ^ b;
      b = a ^ b;
      a = a ^ b;

    4. 按位取反 ~

    • 规则:0 变 1,1 变 0。
    • 注意:涉及补码,~x 通常等于 -x – 1。

    5. 适用范围

    仅适用于整数类型 (byte, short, int, long, char)。运算时小类型自动提升为 int。


    第 39 期:位移运算符 (<<, >>, >>>)

    1. 左移 <<

    • 规则:低位补 0,高位溢出丢弃。
    • 意义:x << n 等价于 x * 2^n。
    • 风险:容易溢出(特别是符号位移入数据位)。

    2. 有符号右移 >>

    • 规则:高位补符号位(正数补 0,负数补 1)。
    • 意义:x >> n 等价于 x / 2^n (向下取整)。
    • 注意:负数右移结果与整数除法略有不同(如 -5 >> 1 为 -3,而 -5 / 2 为 -2)。

    3. 无符号右移 >>>

    • 规则:高位恒补 0。
    • 意义:负数无符号右移会变成很大的正数。常用于处理无符号数据(如 IP 地址)。

    4. 注意事项

    • 位移量超过类型位数时,会对位数取模(如 int 移 32 位相当于移 0 位)。
    • 实际业务中较少使用,多见于算法和底层优化。

    第 40 期:三元运算符 (? 😃

    1. 语法结构

    条件表达式 ? 表达式1 : 表达式2

    • 条件为 true → 结果为表达式 1 的值。
    • 条件为 false → 结果为表达式 2 的值。

    2. 特点

    • 表达式而非语句:必须有返回值,且该返回值必须被使用(赋值或打印)。// int a = 10;
      // a > 5 ? a++ : b++; // 报错!结果未使用

    • 类型一致性:表达式 1 和 2 的类型应一致,否则会自动类型提升。

    3. 适用场景

    • 简单二选一取值。
    • 替代简单的 if-else。String status = age >= 18 ? "成年" : "未成年";
    • 不建议:嵌套过深或逻辑复杂时使用,会降低可读性,此时应使用 if-else。

    结语:恭喜!你已经掌握了 Java 中所有的基础运算符。从算术运算到位运算,再到逻辑控制和条件选择,这些运算符构成了 Java 程序逻辑的基石。下一期我们将进入流程控制的核心——分支结构 (if-else, switch)。


    Java 入门到精通 (第 41-50 期)

    简介:本阶段深入讲解运算符的高级用法(嵌套、优先级、求值顺序)、Java 10+ 新特性 var,并正式进入流程控制的核心——选择结构(if 语句的三种格式、嵌套、switch 语句)。


    第 41 期:三元运算符的嵌套使用

    1. 什么是嵌套

    三元运算符的表达式部分可以再次包含三元运算符,形成嵌套结构。

    • 语法:条件 ? 表达式1 : (条件2 ? 表达式2 : 表达式3)
    • 示例:判断正数、负数或零。String result = num > 0 ? "正数" : (num < 0 ? "负数" : "零");

    2. 经典案例:三个数求最大值

    int max = a > b ? (a > c ? a : c) : (b > c ? b : c);
    // 逻辑:先比 a 和 b,胜者再与 c 比较

    3. 结合性与可读性

    • 右结合性:a > b ? a : b > c ? b : c 等价于 a > b ? a : (b > c ? b : c)。
    • 建议:虽然支持嵌套,但超过一层嵌套后可读性急剧下降。强烈建议使用括号明确意图,或者直接使用 if-else if-else 结构。

    第 42 期:运算符的优先级与结合性

    1. 优先级 (Precedence)

    决定不同运算符谁先计算。

    • 最高:. (成员访问), [] (数组), () (括号/方法调用)。
    • 高:一元运算符 (!, ~, ++, –, +, -)。
    • 中:算术 (*, /, %) → 位移 (<<, >>) → 关系 (<, >) → 相等 (==, !=) → 位与 (&) → 位异或 (^) → 位或 (|) → 逻辑与 (&&) → 逻辑或 (||)。
    • 低:三元 (? :)。
    • 最低:赋值 (=, += 等)。

    2. 结合性 (Associativity)

    当优先级相同时,决定从左往右还是从右往左算。

    • 左结合:大多数运算符(如 +, *, = 以外的运算)。
    • 右结合:一元运算符、三元运算符、赋值运算符。
      • 例:a = b = c 等价于 a = (b = c)。

    3. 核心原则

    • 括号优先级最高:不确定时,永远加括号 ( )。
    • 可读性第一:复杂表达式拆分为中间变量,不要考验读者的记忆力。

    第 43 期:表达式求值顺序详解

    1. 优先级 vs 求值顺序

    • 优先级:决定运算符的结合顺序(先乘除后加减)。
    • 求值顺序:决定操作数的计算顺序。

    2. Java 的规则:从左到右

    Java 规定操作数的求值顺序始终是从左到右。

    int b = (a++) + (a * 2);
    // 1. 计算左边 a++:取原值 10,a 变为 11
    // 2. 计算右边 a*2:此时 a 已是 11,结果为 22
    // 3. 相加:10 + 22 = 32

    3. 最佳实践

    • 避免副作用:不要在表达式中依赖求值顺序(如混用自增和乘法)。
    • 拆分代码:有副作用的操作应单独成行,使用中间变量,提高可读性和可维护性。

    第 44 期:类型推断与 var 关键字 (Java 10+)

    1. 概念

    var 是 Java 10 引入的关键字,用于局部变量类型推断。编译器根据右侧初始化值自动推导左侧变量类型。

    var list = new ArrayList<String>(); // 编译器推断 list 为 ArrayList<String>

    2. 本质

    • 非动态类型:编译后类型依然确定,Java 仍是强类型语言。
    • 语法糖:仅为了减少重复代码,不改变运行时行为。

    3. 使用规则

    • ✅ 可用:局部变量,且必须声明时初始化。
    • ❌ 不可用:
      • 成员变量(字段)。
      • 方法参数。
      • 方法返回值。
      • 只声明不初始化 (var a;)。
      • 初始值为 null。

    4. 注意事项

    • 见名知意:由于类型隐藏,变量名必须清晰表达其含义(如 var userList 而非 var a)。
    • 适度使用:若右侧类型不明显或降低可读性,不建议使用。
    • 基本类型注意:整数默认推断为 int,小数默认推断为 double。

    第 45 期:运算符综合实战练习

    通过以下案例巩固运算符知识:

  • 温度转换:摄氏转华氏,注意浮点数除法。
  • 闰年判断:结合取模 %、逻辑 &&/|| 和三元运算符。boolean isLeap = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
  • 数字拆分:利用 / 和 % 提取百位、十位、个位。
  • 变量交换:
    • 临时变量法(推荐)。
    • 加减法(有溢出风险)。
    • 异或法(面试常见,实际少用)。
  • 水仙花数:提取各位数字并进行幂运算判断。

  • 第 46 期:if 语句的第一种格式

    1. 语法

    if (条件表达式) {
    语句体;
    }

    • 执行流:条件为 true 执行语句体;false 跳过。

    2. 关键注意点

  • 条件必须是 boolean:Java 不支持隐式转换(如 if (1) 非法)。
  • 大括号建议保留:即使只有一行代码也建议写 {},防止后续添加代码时产生逻辑错误。
  • 严禁分号误用:if (cond); {} 会导致大括号内的代码无条件执行。

  • 第 47 期:if…else 语句的第二种格式

    1. 语法

    if (条件表达式) {
    语句体1;
    } else {
    语句体2;
    }

    • 执行流:二选一。条件成立执行语句体1,否则执行语句体2。

    2. 与三元运算符对比

    • 三元运算符:适用于简单的取值操作(表达式,有返回值)。
    • if…else:适用于复杂的逻辑执行(语句,无返回值,可执行多条语句)。

    第 48 期:if…else if…else 第三种格式

    1. 语法

    if (条件1) { ... }
    else if (条件2) { ... }
    else if (条件3) { ... }
    else { ... }

    2. 执行逻辑

    • 从上往下依次判断。
    • 短路特性:一旦某个条件成立,执行对应语句块后,整个结构结束,不再判断后续条件。
    • 最多执行一个分支。

    3. 重要原则

    • 顺序至关重要:范围判断应从大到小或从小到大排列,避免“大区间”在前导致“小区间”永远无法命中。
    • 适用场景:多分支互斥判断(如成绩等级、月份季节)。

    第 49 期:if 语句的嵌套使用

    1. 概念

    在 if 或 else 的代码块内部再编写 if 语句。

    2. else 配对规则

    • 就近原则:else 总是与最近且未配对的 if 配对。
    • 建议:务必使用大括号 {} 明确作用域,避免歧义。

    3. 设计建议

    • 层级限制:嵌套层数尽量不超过 3 层。
    • 优先合并:能用逻辑运算符 (&&, ||) 合并条件的,尽量不用嵌套。
    • 优先 else-if:多个并列条件判断,优先使用 else if 链,而非深层嵌套。

    第 50 期:switch 语句的基础语法

    1. 语法结构

    switch (表达式) {
    case 常量1:
    语句体1;
    break; // 跳出 switch
    case 常量2:
    语句体2;
    break;
    default:
    语句体n;
    break;
    }

    2. 执行流程

  • 计算表达式值。
  • 匹配对应的 case 常量。
  • 执行匹配到的语句体。
  • 遇到 break 跳出 switch;若无 break 则发生穿透(Case Fall-through),继续执行下一个 case。
  • 3. switch vs if

    特性switchif
    适用场景 等值判断 (值不多) 范围判断, 复杂布尔逻辑
    数据类型 byte, short, int, char, String, enum 任意类型
    性能 底层可能优化为跳转表,效率较高 逐条判断

    4. 注意事项

  • Case 必须是常量:不能是变量或范围表达式。
  • Default 位置:可放在任意位置,但通常放最后。所有 case 不匹配时执行。
  • Break 的重要性:除非故意需要穿透,否则每个 case 后都应加上 break。

  • 结语:恭喜!你已经掌握了 Java 基础语法的两大支柱:运算符和选择结构。现在你可以编写具有逻辑判断能力的程序了。接下来的课程将进入循环结构(while, for, do-while),让程序能够处理重复性任务。


    Java 入门到精通 (第 51-60 期)

    简介:本阶段深入讲解 switch 语句的细节(break、穿透、数据类型),对比 if 与 switch 的使用场景,并系统学习循环结构(while, do-while, for),包括嵌套循环、图形打印以及控制跳转语句 break 和 continue。


    第 51 期:switch 语句中 break 的作用与 Case 穿透

    1. break 的作用

    • 功能:跳出 switch 语句块,终止后续执行。
    • 缺失后果:如果没有 break,程序会发生 Case 穿透 (Fall-through)。

    2. Case 穿透

    • 现象:从匹配的 case 开始,一直向下执行所有语句,直到遇到 break 或 switch 结束。
    • 示例:int week = 2;
      switch (week) {
      case 1: System.out.println("周一"); // 不执行
      case 2: System.out.println("周二"); // 执行
      case 3: System.out.println("周三"); // 穿透执行
      default: System.out.println("其他"); // 穿透执行
      }
      // 输出:周二\\n周三\\n其他

    3. 合理利用穿透

    当多个 case 需要执行相同的代码逻辑时,可以利用穿透简化代码:

    int day = 3;
    switch (day) {
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
    System.out.println("工作日");
    break;
    case 6:
    case 7:
    System.out.println("休息日");
    break;
    default:
    System.out.println("无效");
    }

    4. 注意事项

    • 默认建议写 break:除非有意利用穿透,否则每个 case 后都应加 break。
    • 最后一个 break:default 或最后一个 case 后的 break 可省略(因为后面没代码了),但为了规范建议保留。

    第 52 期:switch 支持的数据类型

    1. 支持的类型

    Java switch 表达式支持以下类型:

    • 基本类型:byte, short, int, char。
      • 不支持:long (太大), float/double (精度问题), boolean (只有两个值)。
    • 引用类型:
      • String (Java 7+)。
      • enum (枚举, Java 5+)。
    • 包装类:Byte, Short, Integer, Character (自动拆箱)。

    2. 为什么不支持 Long/Double?

    • switch 底层基于整数值比较实现。
    • long 范围超出 int,转换可能丢失精度。
    • float/double 存在精度误差,相等性判断不可靠。

    3. String 的注意事项

    • case 中的字符串不能为 null,否则会抛出 NullPointerException。
    • 使用 equals() 进行内部比较,性能优于多次 if-else。

    4. Java 12+ 新特性 (Switch 表达式)

    Java 12 引入箭头语法 ->,无需 break,避免穿透:

    String result = switch (day) {
    case 1, 2, 3, 4, 5 -> "工作日";
    case 6, 7 -> "休息日";
    default -> "无效";
    };


    第 53 期:if 与 switch 的选择与区别

    特性if … elseswitch … case
    适用场景 范围判断、复杂逻辑、布尔判断 等值判断、分支较多且固定
    支持类型 任意类型 (结果需为 boolean) byte, short, int, char, String, enum
    灵活性 低 (仅限等值)
    效率 分支多时逐条判断 底层优化为跳转表,效率较高
    可读性 分支多时代码冗长 结构清晰,易于维护

    选择建议

  • 用 switch:判断某个变量是否等于几个固定的值(如星期几、菜单选项、状态码)。
  • 用 if:
    • 范围判断 (>, <, >=)。
    • 复杂条件组合 (&&, ||)。
    • 判断类型不支持 switch (long, double, boolean)。
    • 字符串包含、前缀等非精确匹配。

  • 第 54 期:while 循环的基本结构

    1. 语法

    while (条件表达式) {
    循环体;
    }

    • 流程:先判断条件,若为 true 则执行循环体,再回到判断。

    2. 循环三要素

  • 初始化:循环开始前设置初始状态。
  • 条件判断:决定循环是否继续。
  • 状态改变:每次循环后修改条件,确保最终能退出(否则死循环)。
  • 3. 常见错误

    • 死循环:缺少“状态改变”步骤。
    • 分号误用:while(cond); {} 会导致空循环,大括号内代码只执行一次或不执行。
    • 省略大括号:建议始终保留 {} 以避免逻辑错误。

    第 55 期:do…while 循环与 while 的区别

    1. 语法

    do {
    循环体;
    } while (条件表达式); // 注意末尾必须有分号!

    2. 核心区别

    • while:先判断,后执行。条件不满足时,循环体一次都不执行。
    • do…while:先执行,后判断。无论条件如何,循环体至少执行一次。

    3. 使用场景

    • do…while:适用于必须至少执行一次的场景,如菜单选择、用户输入验证。
    • while:适用于不确定次数,且可能一次都不执行的场景。

    第 56 期:for 循环的标准格式

    1. 语法

    for (初始化; 条件判断; 迭代更新) {
    循环体;
    }

    2. 优势

    • 结构清晰:三要素集中在一行,便于阅读和维护。
    • 防止遗漏:不易忘记更新循环变量。
    • 作用域限制:在初始化部分定义的变量仅在循环内有效。

    3. 执行流程

  • 执行初始化 (仅一次)。
  • 判断条件。
  • 若 true,执行循环体。
  • 执行迭代更新。
  • 回到步骤 2。
  • 4. 省略部分

    三个部分均可省略,但分号必须保留。

    • for (;;) { … } 等价于 while(true) 死循环。
    • 不建议完全省略,会降低可读性。

    第 57 期:for 循环的执行流程图解

    1. 流程详解

    • 初始化:只在循环开始时执行一次。
    • 判断:每次进入循环体前检查。
    • 循环体:执行具体逻辑。
    • 更新:在循环体执行完毕后执行,然后再次判断。

    2. 关键点

    • i++ 的位置:在循环体之后执行。
    • 循环结束后的变量值:通常为导致条件失败的那个值。
      • 例:for(int i=1; i<=3; i++),循环结束后 i 为 4。

    3. 与 while 的等价性

    // for 循环
    for (init; cond; update) { body; }

    // 等价于 while 循环
    init;
    while (cond) {
    body;
    update;
    }


    第 58 期:循环嵌套:打印乘法口诀表

    1. 嵌套规则

    • 外层循环控制行数。
    • 内层循环控制每行的列数(内容)。
    • 执行节奏:外层走一步,内层走完一圈。

    2. 乘法口诀表实现

    for (int i = 1; i <= 9; i++) { // 外层:行
    for (int j = 1; j <= i; j++) { // 内层:列,不超过当前行号
    System.out.print(j + "*" + i + "=" + (j*i) + "\\t");
    }
    System.out.println(); // 每行结束换行
    }

    3. 练习建议

    • 打印三角形、菱形等图形是锻炼嵌套循环逻辑的好方法。
    • 关键在于找出行数 i 与 列数/空格数 之间的数学关系。

    第 59 期:循环嵌套:打印各种图形

    通过调整内层循环的条件,可以打印不同图案:

  • 矩形:内外层循环次数固定。
  • 直角三角形:内层循环次数随外层 i 变化 (j <= i)。
  • 右对齐三角形:每行先打印空格 (j <= rows – i),再打印星号。
  • 等腰三角形 (金字塔):
    • 空格数:rows – i
    • 星号数:2 * i – 1
  • 菱形:分为上半部分(正三角)和下半部分(倒三角)分别打印。

  • 第 60 期:break 跳出循环语句

    1. break 的作用

    • 功能:立即终止当前所在的循环或 switch。
    • 位置:通常放在 if 条件中,满足特定条件时触发。

    2. 在循环中的应用

    • 提前退出:例如查找目标值,找到后立即 break,节省时间。
    • 死循环控制:在 while(true) 中通过条件判断 break 退出。

    3. 嵌套循环中的行为

    • break 只能跳出最近的一层循环(内层)。
    • 若要跳出多层循环,需使用带标签的 break (Labelled Break),见下一期。

    4. 注意事项

    • 作用域限制:只能在循环或 switch 中使用。
    • 后续代码不可达:break 之后的代码无法执行,编译器会报错。
    • 与 return 区别:
      • break:跳出循环,继续执行方法中剩余代码。
      • return:结束整个方法,返回调用者。

    5. 经典案例:素数判断

    boolean isPrime = true;
    for (int i = 2; i < n; i++) {
    if (n % i == 0) {
    isPrime = false;
    break; // 发现因子,不是素数,直接退出
    }
    }


    结语:恭喜!你已经掌握了 Java 流程控制的两大核心支柱:选择结构 (if/switch) 和 循环结构 (while/do-while/for)。现在你可以编写具有复杂逻辑和重复处理能力的程序了。接下来的课程将讲解 continue 语句以及更高级的数组和面向对象编程基础。


    Java 入门到精通 (第 61-70 期)

    简介:本阶段深入讲解循环控制语句(continue、带标签的 break/continue)、死循环的应用,并系统介绍了 Random 和 Math 类。最后通过一系列经典算法案例(猜数字、闰年、水仙花数、斐波那契数列等)综合应用流程控制知识。


    第 61 期:continue 结束单次循环

    1. 作用

    • continue:跳过本次循环中剩余的代码,直接进入下一次循环的判断或更新步骤。
    • 对比 break:break 是彻底终止整个循环;continue 只是跳过当前这一次迭代。

    2. 示例:打印 1-10,跳过 5

    for (int i = 1; i <= 10; i++) {
    if (i == 5) {
    continue; // 跳过打印,直接进行 i++
    }
    System.out.println(i);
    }
    // 输出:1, 2, 3, 4, 6, 7, 8, 9, 10

    3. 注意事项:while 中的死循环陷阱

    在 while 循环中使用 continue 时,必须确保改变循环条件的语句位于 continue 之前,否则会导致死循环。

    int i = 0;
    while (i < 10) {
    if (i == 5) {
    continue; // 跳过了下面的 i++,导致 i 永远为 5,死循环!
    }
    System.out.println(i);
    i++;
    }

    • 建议:在 for 循环中使用 continue 更安全,因为 i++ 在循环头中,一定会执行。

    4. 嵌套循环中的行为

    continue 只能作用于当前所在层的循环。内层的 continue 不会影响外层循环的执行。


    第 62 期:带标签的 break 与 continue

    1. 什么是标签

    给循环起一个名字,格式为 标签名: 循环语句。

    outer: for (int i = 0; i < 10; i++) { ... }

    2. 功能

    • break outer;:直接跳出名为 outer 的外层循环,而不仅仅是当前内层循环。
    • continue outer;:直接跳到名为 outer 的外层循环的下一次迭代。

    3. 使用场景

    主要用于多层嵌套循环中需要一次性跳出所有层级时。但在实际开发中较少使用,通常可以通过标志变量或方法返回来实现,以保持代码可读性。

    4. 面试考点

    Java 中有 goto 关键字吗?

    • 有保留字 goto,但未实现。
    • 带标签的 break/continue 实现了类似 goto 的功能,但仅限于循环内部跳转。

    第 63 期:死循环的概念与应用

    1. 定义

    条件永远为真,循环无法自然结束的循环。

    while (true) { ... }
    for (;;) { ... }
    do { ... } while (true);

    2. 是 Bug 吗?

    不一定。许多程序需要长期运行,故意使用死循环,并在内部通过 break 或 return 控制退出。

    • 常见场景:服务器监听、游戏主循环、菜单系统、监控程序。

    3. 意外死循环的原因

  • 忘记更新循环变量(如漏写 i++)。
  • continue 跳过了更新语句。
  • 循环条件错误(如 i > 0 当 i 初始为 0 且递增时)。
  • 浮点数比较:使用 != 判断浮点数是否达到目标值(因精度问题可能永远不相等)。
  • 4. 如何终止

    • 命令行:Ctrl + C
    • IDE:点击停止按钮

    第 64 期:随机数 Random 类的生成

    1. 基本用法

    import java.util.Random;

    Random r = new Random();
    int num = r.nextInt(10); // 生成 [0, 10) 之间的整数,即 0-9

    2. 生成指定范围 [min, max] 的随机整数

    通用公式:

    int num = r.nextInt(max min + 1) + min;

    • 例如:生成 1-100 → r.nextInt(100) + 1
    • 例如:生成 5-15 → r.nextInt(11) + 5

    3. 其他方法

    • nextDouble(): [0.0, 1.0)
    • nextBoolean(): true 或 false
    • nextInt(): 任意 int 范围

    4. 伪随机数

    • Random 生成的是伪随机数,基于种子计算。
    • 默认构造函数使用当前时间作为种子,保证每次运行结果不同。
    • 若指定种子 new Random(100),则每次生成的序列相同。

    第 65 期:Math 类中的常用数学方法

    1. 特点

    • 位于 java.lang 包,无需导包。
    • 所有方法均为 static,直接通过 Math.方法名() 调用。
    • 类本身是 final,不可继承,构造私有。

    2. 常用方法表

    方法说明示例
    abs(a) 绝对值 Math.abs(-5) → 5
    max(a, b) / min(a, b) 最大值/最小值 Math.max(3, 5) → 5
    pow(a, b) a 的 b 次幂 Math.pow(2, 3) → 8.0
    sqrt(a) 平方根 Math.sqrt(16) → 4.0
    ceil(a) 向上取整 Math.ceil(3.2) → 4.0
    floor(a) 向下取整 Math.floor(3.8) → 3.0
    round(a) 四舍五入 Math.round(3.5) → 4 (long)
    random() 随机 double [0.0, 1.0)

    3. Math.random() vs Random 类

    • Math.random() 底层调用 Random,仅返回 [0.0, 1.0) 的 double。
    • 生成整数需手动转换:(int)(Math.random() * 100) + 1。
    • 推荐使用 Random 类,API 更清晰直观。

    4. 常量

    • Math.PI: 圆周率 π
    • Math.E: 自然常数 e

    第 66 期:流程控制案例——猜数字游戏

    1. 需求

    • 系统生成 1-100 随机数。
    • 用户有 10 次机会猜测。
    • 提示“猜大了”、“猜小了”。
    • 猜对胜利,用完次数失败。
    • 支持一局结束后选择是否重玩。

    2. 核心逻辑结构

    // 外层:控制是否再玩一局 (do-while)
    do {
    // 初始化本轮游戏
    int target = r.nextInt(100) + 1;
    boolean win = false;

    // 内层:控制猜测次数 (for)
    for (int i = 1; i <= 10; i++) {
    // 获取输入
    // 判断大小 (if-else)
    if (guess == target) {
    win = true;
    break; // 猜对,跳出内层循环
    }
    }

    // 判断输赢
    if (!win) System.out.println("失败");

    // 询问是否重玩
    } while (继续游戏);

    3. 知识点综合运用

    • Random: 生成目标数。
    • Scanner: 接收用户输入。
    • for/while: 循环控制。
    • if-else: 逻辑判断。
    • break: 提前退出循环。
    • boolean 标记位: 记录游戏结果状态。

    第 67 期:流程控制案例——判断闰年

    1. 闰年规则

  • 能被 4 整除 且 不能被 100 整除。
  • 或者 能被 400 整除。
  • 2. 代码实现

    推荐写法(逻辑表达式):

    boolean isLeap = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);

    替代写法(嵌套 if):

    if (year % 4 == 0) {
    if (year % 100 == 0) {
    if (year % 400 == 0) isLeap = true;
    else isLeap = false;
    } else {
    isLeap = true;
    }
    } else {
    isLeap = false;
    }

    3. 扩展:判断月份天数

    结合 switch 和闰年判断,确定某年某月的天数。

    • 1,3,5,7,8,10,12月 → 31天
    • 4,6,9,11月 → 30天
    • 2月 → 闰年29天,平年28天

    第 68 期:流程控制案例——水仙花数

    1. 定义

    三位数中,各位数字的立方和等于其本身的数。

    • 例:153=13+53+33153 = 1^3 + 5^3 + 3^3153=13+53+33

    2. 解题思路

  • 遍历 100-999。
  • 拆分个位、十位、百位。
    • 个位:n % 10
    • 十位:n / 10 % 10
    • 百位:n / 100
  • 计算立方和并比较。
  • 3. 代码实现

    for (int i = 100; i <= 999; i++) {
    int ge = i % 10;
    int shi = i / 10 % 10;
    int bai = i / 100;

    if (ge*ge*ge + shi*shi*shi + bai*bai*bai == i) {
    System.out.println(i);
    }
    }
    // 结果:153, 370, 371, 407

    4. 扩展:取任意位数字

    公式:num / (int)Math.pow(10, n) % 10 (n 从右向左索引,0开始)。


    第 69 期:流程控制案例——统计位数与求和

    1. 需求

    输入一个整数,输出:

  • 位数
  • 各位数字之和
  • 逆序数
  • 2. 核心算法:循环取余

    利用 while 循环,每次取个位并除以 10,直到数为 0。

    int temp = Math.abs(num); // 处理负数和0
    int count = 0;
    int sum = 0;
    int reverse = 0;

    if (temp == 0) {
    count = 1; // 特殊处理0
    } else {
    while (temp > 0) {
    int digit = temp % 10;
    count++;
    sum += digit;
    reverse = reverse * 10 + digit; // 拼接逆序数
    temp /= 10;
    }
    }

    3. 扩展:回文数判断

    若 reverse == Math.abs(num),则为回文数。


    第 70 期:流程控制案例——斐波那契数列

    1. 定义

    数列:1, 1, 2, 3, 5, 8, 13…
    规律:F(n)=F(n−1)+F(n−2)F(n) = F(n-1) + F(n-2)F(n)=F(n1)+F(n2) (n≥3n \\ge 3n3)

    2. 迭代法实现(推荐)

    使用三个变量滚动更新,空间复杂度 O(1)O(1)O(1)

    int n = 20;
    int a = 1, b = 1;
    System.out.print(a + " " + b);

    for (int i = 3; i <= n; i++) {
    int c = a + b;
    System.out.print(" " + c);
    a = b; // 前移
    b = c; // 更新当前
    }

    3. 其他实现方式

    • 数组存储:适合需要保存历史数据的场景。int[] fib = new int[n];
      fib[0] = 1; fib[1] = 1;
      for(int i=2; i<n; i++) fib[i] = fib[i1] + fib[i2];

    • 递归:代码简洁但效率低(重复计算),不推荐用于大数值。

    4. 注意事项

    • 数据溢出:int 最多支持到第 46 项左右,更大需用 long 或 BigInteger。
    • 应用场景:爬楼梯问题、兔子繁殖、动态规划入门。

    结语:恭喜!你已经完成了 Java 基础语法中流程控制的所有核心内容。从简单的分支判断到复杂的循环嵌套,再到经典的算法案例,你的逻辑思维能力和编程实战能力得到了显著提升。接下来,我们将进入数据结构的基础——数组的学习。


    Java 入门到精通 (第 71-80 期)

    简介:本阶段系统讲解 Java 数组(Array)。从一维数组的概念、内存模型、声明初始化、遍历操作,到常见的算法案例(最大值、求和、逆序),再到二维数组的结构与遍历。重点解析数组的底层原理及常见异常处理。


    第 71 期:数组的概念与内存分配原理

    1. 为什么需要数组

    • 痛点:存储大量相同类型数据时,定义多个变量繁琐且难以管理(如求平均分)。
    • 解决方案:数组是一个容器,可以一次性存储多个相同类型的数据。

    2. 数组的核心特点

    • 类型一致:所有元素必须是同一种数据类型。
    • 长度固定:创建后长度不可改变。
    • 索引访问:通过从 0 开始的整数索引访问元素。
    • 连续存储:在内存中占据连续的空间。

    3. 内存模型

    Java 内存主要分为栈(Stack)和堆(Heap):

    • 栈(Stack):存储局部变量(包括引用变量的地址)。
    • 堆(Heap):存储 new 出来的对象(包括数组对象本身)。

    引用类型机制:

    • 数组变量(如 int[] arr)存储在栈中,保存的是指向堆中数组对象的地址。
    • 数组的实际元素数据存储在堆中。

    栈内存 堆内存
    +——+ +———–+
    | arr | ———–> | int[5] |
    +——+ +———–+
    (地址) | 0: 90 |
    | 1: 85 |
    | … |
    +———–+

    4. 默认初始化值

    数据类型默认值
    整数 (byte, short, int, long) 0
    浮点数 (float, double) 0.0
    字符 (char) '\\u0000'
    布尔 (boolean) false
    引用类型 (String, 对象等) null

    第 72 期:一维数组的声明与动态初始化

    1. 数组声明

    推荐写法:数据类型[] 数组名;

    • 注意:声明时不能指定长度。

    2. 动态初始化

    只指定长度,由系统赋予默认值。

    // 格式:new 数据类型[长度]
    int[] arr = new int[5];

    3. 数组访问与长度

    • 访问元素:数组名[索引]。索引范围:0 到 length – 1。
    • 获取长度:数组名.length。
      • 重要区别:length 是属性(无括号),String 的 length() 是方法(有括号)。

    4. 数组遍历

    使用 for 循环,索引从 0 遍历至 arr.length – 1。

    for (int i = 0; i < arr.length; i++) {
    System.out.println(arr[i]);
    }

    5. 常见错误

    • ArrayIndexOutOfBoundsException:索引越界(访问了 <0 或 >=length 的索引)。
    • NullPointerException:数组变量为 null 时访问元素。

    第 73 期:一维数组的静态初始化

    1. 静态初始化

    创建数组时直接指定具体元素值,系统自动计算长度。

    2. 两种格式

    • 标准格式:int[] arr = new int[]{1, 2, 3};
    • 简化格式(推荐):int[] arr = {1, 2, 3};
      • 注意:简化格式只能在声明同时使用,不能用于后续赋值(如 arr = {1,2} 是错误的)。

    3. 动态 vs 静态选择

    • 知道元素内容 → 用静态初始化。
    • 只知道长度,内容未知或后续生成 → 用动态初始化。

    4. 注意事项

    • 数组一旦创建,长度不可变。
    • 直接打印数组对象输出的是哈希地址(如 [I@1b6d3586),需遍历或使用 Arrays.toString() 查看内容。

    第 74 期:数组的遍历与 length 属性

    1. 两种遍历方式对比

    特性普通 for 循环增强 for 循环 (foreach)
    语法 for(int i=0; i<arr.length; i++) for(type var : arr)
    是否有索引 有 (i)
    能否修改元素 能 (arr[i] = val) 不能 (修改变量副本不影响原数组)
    适用场景 需要索引、修改元素、查找位置 仅读取元素、简单遍历

    2. 典型应用

    • 求和:累加所有元素。
    • 求平均值:sum / length。
      • 陷阱:注意整数除法精度丢失,建议先转换为 double:(double) sum / length。

    3. 注意事项

    • 空数组 (length=0) 遍历时循环体不执行,安全。
    • null 数组遍历时会报 NullPointerException。

    第 75 期:数组的最小值与最大值获取

    1. 核心思路(擂台法)

  • 假设第一个元素为最大值/最小值 (max = arr[0])。
  • 从第二个元素开始遍历。
  • 若当前元素大于 max,则更新 max。
  • 2. 关键细节

    • 初始值必须来自数组:不能设为 0,否则全负数数组结果错误。
    • 起始索引:从 1 开始比较(因为 0 已作为初始值)。
    • 同时求最值:在一次遍历中同时更新 max 和 min,提高效率。

    3. 获取最值的索引

    记录最大/最小值的索引 index,当发现更优值时更新 index。


    第 76 期:数组元素的求和与平均值

    1. 求和与平均值代码模板

    int sum = 0;
    for (int num : arr) {
    sum += num;
    }
    double avg = (double) sum / arr.length; // 强制转换防止整数截断

    2. 进阶统计

    • 单次遍历:可同时计算总和、最大值、最小值。
    • 多次遍历:若需统计“大于平均值的个数”,需先算出平均值,再二次遍历统计。

    3. 溢出风险

    • 若数组元素很大或数量很多,sum 可能超出 int 范围,建议使用 long 或 double 存储累加和。

    第 77 期:数组的逆序操作

    1. 概念

    • 逆序:修改原数组,使元素顺序颠倒(原地交换)。
    • 倒着打印:仅改变输出顺序,不修改原数组。

    2. 实现逻辑

    首尾交换:索引 i 与 length – 1 – i 交换。
    只需遍历到 length / 2。

    3. 代码实现

    方法一:For 循环

    for (int i = 0; i < arr.length / 2; i++) {
    int temp = arr[i];
    arr[i] = arr[arr.length 1 i];
    arr[arr.length 1 i] = temp;
    }

    方法二:双指针 While 循环

    int left = 0;
    int right = arr.length 1;
    while (left < right) {
    int temp = arr[left];
    arr[left] = arr[right];
    arr[right] = temp;
    left++;
    right;
    }


    第 78 期:数组的拷贝与扩容

    1. 为什么需要扩容

    数组长度固定。若需增加容量,需新建更大数组并拷贝数据。

    2. 四种拷贝方式

  • 手动循环:灵活但繁琐。
  • System.arraycopy():原生方法,效率高,参数多(源数组、源起始位、目标数组、目标起始位、拷贝长度)。
  • Arrays.copyOf():最方便,返回新数组。常用于扩容。arr = Arrays.copyOf(arr, arr.length * 2); // 扩容一倍
  • clone():最简单,复制整个数组。
  • 3. 扩容策略

    通常按倍数扩容(如 1.5 倍或 2 倍),以减少频繁扩容带来的性能开销(时间换空间)。


    第 79 期:数组的常见异常

    1. ArrayIndexOutOfBoundsException (索引越界)

    • 原因:访问索引 < 0 或 >= length。
    • 常见场景:循环条件写错 (<=)、索引计算错误。
    • 预防:坚持使用 i < arr.length。

    2. NullPointerException (空指针)

    • 原因:数组变量为 null 时访问属性或方法。
    • 常见场景:只声明未初始化、手动赋值为 null、引用类型数组元素默认为 null。
    • 预防:使用前检查 if (arr != null);引用类型数组元素使用前需确认非 null。

    3. 调试技巧

    学会阅读异常堆栈信息,定位报错行数和具体原因。


    第 80 期:二维数组的理解与内存结构

    1. 概念

    • 定义:数组的数组。
    • 结构:像表格一样,有行(Row)和列(Column)。
    • 本质:Java 中没有真正的多维数组,二维数组是一个一维数组,其每个元素又是一个一维数组的引用。

    2. 内存结构

    • 外层数组(行)存储在堆中,其元素存储的是内层数组(列)的地址。
    • 支持不规则数组(锯齿数组),即每行的长度可以不同。

    3. 声明与初始化

    • 规则二维数组:int[][] arr = new int[3][5]; (3行5列)
    • 不规则二维数组:int[][] arr = new int[3][]; // 指定行数
      arr[0] = new int[3]; // 第一行3个元素
      arr[1] = new int[5]; // 第二行5个元素

    4. 访问与遍历

    • 访问:arr[行索引][列索引]。
    • 长度:
      • arr.length:行数。
      • arr[i].length:第 i 行的列数。
    • 遍历:双重循环。
      • 外层循环控制行 (i < arr.length)。
      • 内层循环控制列 (j < arr[i].length)。

    for (int i = 0; i < arr.length; i++) {
    for (int j = 0; j < arr[i].length; j++) {
    System.out.print(arr[i][j] + " ");
    }
    System.out.println();
    }


    结语:恭喜!你已经掌握了 Java 中最重要的数据结构之一——数组。从一维到二维,从基础操作到内存原理,这些知识是后续学习集合框架(Collection)和面向对象编程的基石。接下来,我们将进入面向对象编程 (OOP) 的世界,探索类与对象的核心概念。


    Java 入门到精通 (第 81-90 期)

    简介:本阶段深入讲解二维数组及其操作,介绍 Arrays 工具类与经典算法(二分查找、冒泡/选择/插入排序),并通过综合案例(抽奖系统、成绩管理系统)巩固数组应用。最后引入“方法”概念,详解方法的定义、调用及参数传递机制(值传递)。


    第 81 期:二维数组的初始化与遍历

    1. 静态初始化

    直接指定元素值,支持规则和不规则(锯齿)数组。

    // 标准格式
    int[][] arr = new int[][]{{1, 2}, {3, 4, 5}};

    // 简化格式(推荐)
    int[][] arr = {{1, 2}, {3, 4, 5}};

    2. 遍历

    • 普通 For 循环:需两层循环,外层控制行,内层控制列。注意使用 arr[i].length 获取每行长度。
    • 增强 For 循环:更简洁。for (int[] row : arr) {
      for (int num : row) {
      System.out.print(num + " ");
      }
      System.out.println();
      }

    3. 经典案例:杨辉三角

    • 规律:每行首尾为 1;中间元素 arr[i][j] = arr[i-1][j-1] + arr[i-1][j]。
    • 实现:先动态创建每一行的数组(长度为 i+1),填充数据后打印。

    第 82 期:Arrays 工具类常用方法

    java.util.Arrays 提供了丰富的数组操作静态方法。

    方法说明示例
    toString(arr) 转字符串,方便打印一维数组 [1, 2, 3]
    deepToString(arr) 转字符串,用于多维数组 [[1, 2], [3, 4]]
    sort(arr) 升序排序 Arrays.sort(arr)
    binarySearch(arr, key) 二分查找(数组必须有序) 返回索引或负数
    copyOf(arr, len) 复制数组,可指定新长度 短则截断,长则补默认值
    fill(arr, val) 填充数组所有元素 Arrays.fill(arr, 0)
    equals(a1, a2) 比较内容是否相同 true/false

    第 83 期:二分查找算法实现

    1. 前提条件

    • 数组必须是有序的。

    2. 核心逻辑

  • 定义左边界 left = 0,右边界 right = length – 1。
  • 当 left <= right 时循环:
    • 计算中点 mid = left + (right – left) / 2(防止溢出)。
    • 若 arr[mid] == target,返回 mid。
    • 若 arr[mid] < target,说明目标在右侧,left = mid + 1。
    • 若 arr[mid] > target,说明目标在左侧,right = mid – 1。
  • 循环结束未找到,返回 -1。
  • 3. 复杂度

    • 时间复杂度:O(log⁡n)O(\\log n)O(logn),效率极高。
    • 空间复杂度:O(1)O(1)O(1)

    第 84 期:冒泡排序算法详解

    1. 思路

    重复遍历数组,比较相邻元素,若顺序错误则交换。每一轮将最大元素“冒泡”至末尾。

    2. 代码结构

    for (int i = 0; i < arr.length 1; i++) { // n-1 轮
    for (int j = 0; j < arr.length 1 i; j++) { // 每轮减少比较次数
    if (arr[j] > arr[j + 1]) {
    // 交换
    }
    }
    }

    3. 优化

    添加 boolean swapped 标志位。若某轮无交换,说明已有序,提前终止。

    4. 特性

    • 时间复杂度:平均 O(n2)O(n^2)O(n2),最好 O(n)O(n)O(n)(已有序)。
    • 稳定性:稳定。
    • 空间复杂度:O(1)O(1)O(1)

    第 85 期:选择排序算法详解

    1. 思路

    每一轮从待排序部分选出最小元素,与待排序部分的第一个元素交换。

    2. 代码结构

    for (int i = 0; i < arr.length 1; i++) {
    int minIndex = i;
    for (int j = i + 1; j < arr.length; j++) {
    if (arr[j] < arr[minIndex]) {
    minIndex = j;
    }
    }
    if (minIndex != i) {
    // 交换 arr[i] 和 arr[minIndex]
    }
    }

    3. 对比冒泡

    • 交换次数少:每轮最多交换 1 次,优于冒泡。
    • 稳定性:不稳定(相等元素相对位置可能改变)。
    • 时间复杂度始终为 O(n2)O(n^2)O(n2)

    第 86 期:插入排序算法详解

    1. 思路

    类似打扑克牌理牌。将数组分为已排序和待排序两部分,每次取出待排序第一个元素,插入到已排序部分的正确位置。

    2. 代码结构

    for (int i = 1; i < arr.length; i++) {
    int temp = arr[i];
    int j = i 1;
    // 边找边移
    while (j >= 0 && arr[j] > temp) {
    arr[j + 1] = arr[j];
    j;
    }
    arr[j + 1] = temp;
    }

    3. 特性

    • 最好情况:O(n)O(n)O(n)(已有序)。
    • 最坏情况:O(n2)O(n^2)O(n2)(完全逆序)。
    • 稳定性:稳定。
    • 适用场景:数据量小或基本有序时效率很高,是实际开发中常用的基础排序(如 JDK 源码中的混合排序)。

    第 87 期:数组综合案例——抽奖系统

    1. 需求

    • 奖池抽取奖品,不重复。
    • 查看剩余奖品、已中奖品。

    2. 核心技巧:模拟删除

    由于数组长度固定,无法直接删除元素。

    • 策略:用变量 count 记录有效奖品数量。
    • 移除逻辑:随机抽取索引 index 的元素,将最后一个有效元素 (prizes[count-1]) 复制到 index 位置,然后 count–。
    • 优点:无需移动大量元素,效率高(适用于不关心顺序的场景)。

    第 88 期:数组综合案例——成绩管理系统

    1. 功能模块

    • 增:添加到数组末尾,增加计数。
    • 查:遍历打印。
    • 统:一次遍历计算总分、最高、最低。
    • 排:使用 Arrays.copyOf 复制副本后排序,保留原顺序。
    • 搜:遍历查找或二分查找(需先排序)。
    • 段:统计各分数段人数。

    2. 设计模式

    • 定长数组 + 计数器:这是使用原生数组模拟动态列表的标准做法。
    • 菜单驱动:while(true) + switch 实现交互界面。

    第 89 期:方法(Method)的定义与调用

    1. 概念

    方法是完成特定功能的代码块,实现代码复用和模块化。

    2. 定义格式

    修饰符 返回值类型 方法名(参数列表) {
    方法体;
    return 返回值; // void 类型可不写或只写 return
    }

    3. 调用

    • 无返回值:方法名(实参);
    • 有返回值:数据类型 变量 = 方法名(实参);

    4. 注意事项

    • 方法必须在类中定义,不可嵌套。
    • 参数个数、类型、顺序需匹配。
    • return 语句立即结束方法执行。

    第 90 期:方法的参数传递(值传递)

    Java 中只有值传递,没有引用传递。

    1. 基本类型参数

    • 传递的是值的副本。
    • 方法内修改形参,不影响外部实参。

    2. 引用类型参数(如数组、对象)

    • 传递的是地址值的副本。
    • 形参和实参指向堆内存中的同一个对象。
    • 修改对象内容(如 arr[0] = 100):会影响外部实参(因为操作的是同一个对象)。
    • 重新赋值(如 arr = new int[]{…}):不会影响外部实参(因为只是改变了副本的指向,实参仍指向原对象)。

    3. 总结口诀

    • 改值不改址,外面看不见(基本类型)。
    • 改址不改值,外面也看不见(引用类型重新 new)。
    • 既改值又改址(通过引用来修改内部状态),外面看得到。

    结语:恭喜!你已经掌握了 Java 基础语法的核心支柱:数组与方法。数组让你能够批量处理数据,方法让你能够组织和管理逻辑。接下来,我们将进入面向对象编程(OOP)的世界,学习如何封装数据与行为,构建更复杂的程序结构。


    Java 入门到精通 (第 91-100 期)

    简介:本阶段深入讲解方法的高级特性(重载、可变参数、递归),介绍常用类库(String, StringBuilder, Date/Time, System),并回顾整个基础语法阶段的学习路线,为进入面向对象编程(OOP)打下坚实基础。


    第 91 期:方法的重载(Overload)

    1. 概念

    在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可。

    • 目的:功能相似的方法使用相同名称,提高代码可读性和易用性(如 System.out.println)。

    2. 判定标准

    • 必须满足:
    • 同一个类中。
    • 方法名相同。
    • 参数列表不同(参数个数、参数类型、参数顺序不同)。
    • 无关因素:
      • 返回值类型不同(不算重载,编译器无法区分调用哪个)。
      • 修饰符不同。
      • 参数名不同。

    3. 方法签名

    • 定义:方法名 + 参数列表。
    • 作用:唯一标识一个方法。重载即意味着方法签名不同。

    第 92 期:可变参数(VarArgs)的使用

    1. 概念

    方法的参数个数可以变化,支持 0 个、1 个或多个参数。

    2. 语法

    public static void methodName(Type... paramName) { ... }

    • 本质是一个数组。在方法内部,paramName 被视为 Type[] 数组。

    3. 规则

  • 一个方法最多只能有一个可变参数。
  • 可变参数必须位于参数列表的最后。
  • 可以直接传入数组,也可以逐个传入元素。
  • 4. 示例

    public static int sum(int... nums) {
    int sum = 0;
    for (int num : nums) sum += num;
    return sum;
    }
    // 调用:sum(), sum(1), sum(1, 2, 3) 均合法


    第 93 期:方法的返回值与 void 关键字

    1. 返回值类型

    • 有返回值:指定具体数据类型(基本类型或引用类型)。方法体中必须包含 return 值;,且所有执行路径都必须有返回。
    • 无返回值:使用 void。方法体中可以没有 return,或者仅写 return; 用于提前结束方法。

    2. return 的作用

  • 返回结果给调用者。
  • 结束当前方法的执行。
  • 3. 选择原则

    • 需要获取计算结果 → 有返回值。
    • 仅执行操作(如打印、修改对象状态) → void。

    第 94 期:方法的递归调用

    1. 概念

    方法在执行过程中调用自身。

    2. 核心要素

  • 递归出口(Base Case):终止条件,防止无限递归导致栈溢出(StackOverflowError)。
  • 递归体(Recursive Step):将大问题分解为结构相同但规模更小的子问题。
  • 3. 经典案例

    • 阶乘:n!=n×(n−1)!n! = n \\times (n-1)!n!=n×(n1)!,出口 1!=11! = 11!=1
    • 斐波那契数列:F(n)=F(n−1)+F(n−2)F(n) = F(n-1) + F(n-2)F(n)=F(n1)+F(n2),出口 F(1)=1,F(2)=1F(1)=1, F(2)=1F(1)=1,F(2)=1
      • 注意:朴素递归实现斐波那契效率低(重复计算),大数据量下建议使用循环或记忆化搜索。

    4. 优缺点

    • 优点:代码简洁,逻辑清晰,适合解决天然递归问题(如树遍历、汉诺塔)。
    • 缺点:性能开销大(栈空间占用),可能存在重复计算,调试困难。
    • 建议:能用循环解决的优先用循环;特殊场景用递归。

    第 95 期:Debug 调试模式进阶

    1. 断点(Breakpoint)

    程序运行到标记位置暂停,便于观察状态。

    • 行断点:常规断点。
    • 条件断点:满足特定条件(如 i == 50)时才暂停,极大提高循环调试效率。

    2. 常用快捷键

    快捷键功能说明
    F8 Step Over 单步执行,不进入方法内部
    F7 Step Into 单步执行,进入方法内部
    Shift+F8 Step Out 跳出当前方法,回到调用处
    F9 Resume 继续运行至下一个断点

    3. 调试面板

    • Variables:查看当前变量值,支持修改变量测试。
    • Frames (Call Stack):查看方法调用栈,回溯调用来源。

    第 96 期:String 类的常用方法详解

    String 是不可变字符序列,所有修改操作均返回新字符串。

    1. 获取与判断

    • length(): 长度。
    • charAt(index): 获取指定索引字符。
    • indexOf(str): 查找首次出现索引,未找到返回 -1。
    • equals(obj): 比较内容(严禁使用 == 比较 String 内容)。
    • contains(str): 是否包含子串。
    • startsWith(str) / endsWith(str): 前缀/后缀判断。
    • isEmpty(): 是否为空串(长度为0)。

    2. 转换与截取

    • toUpperCase() / toLowerCase(): 大小写转换。
    • toCharArray(): 转为字符数组。
    • substring(beginIndex) / substring(begin, end): 截取子串(左闭右开 [begin, end))。
    • replace(old, new): 替换所有匹配项。
    • split(regex): 分割字符串,返回数组。
    • trim(): 去除首尾空格。

    3. 注意事项

    • 频繁拼接字符串不要用 +,会导致大量临时对象产生,应使用 StringBuilder。
    • 常量池优化:编译期确定的字符串常量会复用。

    第 97 期:StringBuilder 与 StringBuffer

    1. 为什么需要可变字符串

    String 不可变,多次拼接会产生大量垃圾对象,效率极低。StringBuilder 底层基于可扩容的字符数组,修改原对象,效率高。

    2. 常用方法

    • append(…): 追加内容(支持链式调用)。
    • insert(index, str): 插入内容。
    • delete(start, end): 删除内容。
    • replace(start, end, str): 替换内容。
    • reverse(): 反转字符串。
    • toString(): 转换为 String 对象。

    3. StringBuilder vs StringBuffer

    • StringBuilder: 非线程安全,效率高。单线程首选。
    • StringBuffer: 线程安全(synchronized 修饰),效率较低。多线程场景使用。

    4. 性能对比

    在循环中进行大量字符串拼接时,StringBuilder 比 String + 快数个数量级。


    第 98 期:日期时间类

    1. 历史演进

    • 第一代:Date (java.util.Date),设计缺陷多,大部分方法已废弃。
    • 第二代:Calendar,复杂且月份从 0 开始,易出错。
    • 第三代(推荐):Java 8 API (java.time 包)。

    2. Java 8 新 API 核心类

    • LocalDate: 只包含日期(年月日)。
    • LocalTime: 只包含时间(时分秒)。
    • LocalDateTime: 包含日期和时间。
    • 特点:不可变、线程安全、API 直观、月份从 1 开始。

    3. 常用操作

    • 获取:now(), of(year, month, day…)。
    • 修改:plusDays(n), minusMonths(n), withYear(n)(返回新对象)。
    • 格式化:DateTimeFormatter(线程安全)。
    • 计算间隔:Duration (时间差), Period (日期间隔)。

    第 99 期:System 类常用方法

    System 是系统工具类,所有成员均为静态。

    1. 输入输出

    • System.out: 标准输出(控制台)。
    • System.err: 标准错误输出(通常红色显示)。
    • System.in: 标准输入流。

    2. 时间与性能

    • currentTimeMillis(): 毫秒级时间戳,常用于计算代码执行耗时。
    • nanoTime(): 纳秒级高精度计时,用于微基准测试。

    3. 其他实用方法

    • arraycopy(src, srcPos, dest, destPos, length): 高效数组拷贝。
    • getProperty(key): 获取系统属性(如 OS 名称、Java 版本)。
    • exit(status): 退出 JVM(0 正常,非 0 异常)。
    • gc(): 建议 JVM 执行垃圾回收(仅为建议,不保证立即执行)。

    第 100 期:基础语法阶段总结与回顾

    1. 学习路线回顾

    • 环境搭建:JDK/JRE/JVM 关系,Hello World。
    • 基础语法:变量、数据类型、运算符、Scanner。
    • 流程控制:if/switch 分支,while/for/do-while 循环,break/continue。
    • 数组:一维/二维数组,Arrays 工具类,排序算法(冒泡/选择/插入),二分查找。
    • 方法与常用类:方法定义/重载/递归,String/StringBuilder,日期时间,System。

    2. 核心思想提升

    • 模块化:将大问题拆解为小方法。
    • 复用意识:避免重复代码。
    • 调试能力:熟练使用 IDEA Debug 工具定位 Bug。
    • 算法思维:掌握基础的数据处理逻辑。

    3. 纯过程式 vs 面向对象

    • 目前所学均为纯过程式编程(数据与方法分离)。
    • 随着项目规模扩大,过程式编程维护成本增加。
    • 下一步:进入面向对象编程 (OOP),学习类、对象、封装、继承、多态,这是 Java 的核心灵魂。

    4. 结语

    恭喜完成 Java 基础语法 100 期学习!地基已打牢,接下来将开启面向对象的新篇章。


    祝贺! 你已经完成了 Java 基础语法的全面学习。现在你具备了编写结构化程序的能力。请准备好迎接下一阶段的挑战:面向对象编程 (OOP)。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 【Java入门到精通】*基础篇
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!