基础语法
# 01.基础语法
# 目录介绍
- 1.1 Java快速介绍
- 1.2 Java开发环境
- 1.3 helloWorld
- 1.4 编译Java
- 1.5 多种注释使用
- 1.6 包(Package)
- 1.7 修饰符
- 1.8 标识符
- 1.9 关键字
# 1.1 Java快速介绍
# 1.1.1 Java语言介绍
Java 是一种面向对象的、跨平台的编程语言,广泛应用于企业级后端开发、Android 应用开发、大数据处理等领域。
它由 James Gosling 于 1995 年在 Sun Microsystems 发布,后被 Oracle 公司收购。Java 的核心理念是 "Write Once, Run Anywhere"(一次编写,到处运行)。
注意:Java 是强类型语言,所有变量必须先声明类型再使用,类型检查在编译时完成。
# 1.1.2 Java的特点
- 面向对象:一切皆对象(基本类型除外),支持封装、继承、多态。
- 跨平台:通过 JVM(Java 虚拟机)实现,编译后的字节码可以在任何安装了 JVM 的平台上运行。
- 自动内存管理:有垃圾回收机制(GC),程序员不需要手动管理内存(不像 C++ 的
new/delete)。 - 安全性高:内置安全机制,如字节码验证、沙箱机制等。
- 多线程支持:语言级别支持多线程编程,提供了
Thread类和synchronized关键字。 - 丰富的标准库:提供了大量的类库(集合框架、IO、网络、并发等)。
# 1.1.3 Java平台体系
Java 平台分为三大体系:
- Java SE(Standard Edition):标准版,包含核心类库,是其他两个版本的基础。
- Java EE(Enterprise Edition):企业版,用于开发大型分布式企业级应用(如 Servlet、JSP、EJB)。
- Java ME(Micro Edition):微型版,用于嵌入式设备和移动设备(目前使用较少)。
# 1.1.4 Java应用领域
- 企业级后端:Spring Boot、Spring Cloud 等框架广泛用于 Web 后端开发。
- Android 开发:Android 应用的主要开发语言之一(配合 Kotlin)。
- 大数据:Hadoop、Spark、Flink 等大数据框架都是 Java/Scala 编写的。
- 金融系统:银行、证券等对稳定性要求极高的系统。
- 中间件:Tomcat、Netty、Dubbo 等。
# 1.1.5 Java的版本
Java 版本不断更新,主要版本包括:
- JDK 1.0(1996):第一个正式版本。
- JDK 5(2004):引入泛型、注解、增强 for 循环、枚举等。
- JDK 8(2014):引入 Lambda 表达式、Stream API、Optional 等(目前使用最广泛)。
- JDK 11(2018):长期支持版本(LTS)。
- JDK 17(2021):长期支持版本(LTS),引入密封类等。
- JDK 21(2023):最新长期支持版本(LTS),引入虚拟线程等。
# 1.1.6 综合案例:Java版本特性速查
编写一个程序,打印当前 JDK 版本信息和 Java 平台的核心特性,帮助理解 Java 的生态体系:
public class JavaFeatureOverview {
public static void main(String[] args) {
// 获取当前运行环境信息
String version = System.getProperty("java.version");
String vmName = System.getProperty("java.vm.name");
String osName = System.getProperty("os.name");
System.out.println("=== Java 环境信息 ===");
System.out.println("Java 版本:" + version);
System.out.println("虚拟机:" + vmName);
System.out.println("操作系统:" + osName);
System.out.println("\n=== Java 核心特性 ===");
String[] features = {
"面向对象:封装、继承、多态",
"跨平台:Write Once, Run Anywhere",
"自动内存管理:垃圾回收(GC)",
"强类型语言:编译时类型检查",
"多线程支持:语言级别内置",
"丰富标准库:集合、IO、网络、并发"
};
for (int i = 0; i < features.length; i++) {
System.out.println((i + 1) + ". " + features[i]);
}
}
}
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
案例涉及知识点:System.getProperty() 获取系统属性、数组遍历、字符串拼接、main 方法入口。
# 1.1.7 训练题
选择题:以下哪个不是 Java 的特点?
- A. 跨平台 B. 自动内存管理 C. 支持指针运算 D. 面向对象
填空题:Java 的三大平台体系分别是 Java ___、Java ___、Java ___。
判断题:Java 程序编译后生成的是机器码,可以直接在 CPU 上运行。( )
简答题:解释 "Write Once, Run Anywhere" 的含义,并说明 Java 是如何实现这一目标的。
思考题:Java 8 是目前使用最广泛的版本,请列举 Java 8 引入的至少3个重要新特性,并思考为什么企业迁移到更新版本(如 JDK 17、JDK 21)的速度较慢?
# 1.2 Java开发环境
# 1.2.1 JDK是什么
JDK(Java Development Kit) 是 Java 开发工具包,包含了编译、运行、调试 Java 程序所需的所有工具。
JDK 包含:
javac:Java 编译器,将.java源文件编译为.class字节码文件。java:Java 运行命令,启动 JVM 执行字节码。javadoc:文档生成工具。jar:打包工具。- JRE(Java 运行环境)。
# 1.2.2 JRE和JVM
JRE(Java Runtime Environment):Java 运行时环境,包含 JVM 和核心类库。只需要运行 Java 程序(不需要开发)的用户安装 JRE 即可。
JVM(Java Virtual Machine):Java 虚拟机,是 Java 跨平台的核心。它负责将字节码(.class 文件)翻译成对应平台的机器码。
三者的关系:
JDK = JRE + 开发工具(javac, javadoc, jar 等)
JRE = JVM + 核心类库
2
JVM 架构原理:JVM 的核心由类加载器(ClassLoader)、运行时数据区(方法区、堆、栈、程序计数器、本地方法栈)和执行引擎三部分组成。类加载器负责将 .class 文件加载到内存;运行时数据区管理程序运行期间的内存分配;执行引擎包含解释器和 JIT 编译器,负责将字节码转换为机器码执行。垃圾回收器(GC)运行在堆区域,自动回收不再被引用的对象占用的内存。
对比 C++:C++ 是直接编译为机器码的,不同平台需要重新编译。而 Java 是先编译为字节码,再由 JVM 解释/编译执行,所以能跨平台。
# 1.2.3 JDK安装配置
下载 JDK:从 Oracle 官网或 OpenJDK 下载对应平台的 JDK。
配置环境变量:
# macOS/Linux:在 ~/.bash_profile 或 ~/.zshrc 中添加
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home
export PATH=$JAVA_HOME/bin:$PATH
# 验证安装
java -version
javac -version
2
3
4
5
6
7
# 1.2.4 IDE开发环境
IDE 集成了编译器、编辑器、调试器等工具,提供更便捷的开发体验。以下是常用的 Java IDE:
- IntelliJ IDEA(推荐):JetBrains 开发,功能最强大,社区版免费。
- Eclipse(跨平台):开源 IDE,插件丰富。
- VS Code:配合 Java 插件也可以进行 Java 开发。
# 1.2.5 在线编译器
如果你不想安装本地环境,可以使用在线编译器快速测试代码:
OnlineGDB:https://www.onlinegdb.com/online_java_compiler
JDoodle:https://www.jdoodle.com/online-java-compiler
# 1.2.6 综合案例:JDK环境检测工具
编写一个程序,自动检测当前 Java 开发环境的关键信息:
public class JdkEnvironmentChecker {
public static void main(String[] args) {
System.out.println("=== JDK 环境检测 ===");
System.out.println("Java 版本:" + System.getProperty("java.version"));
System.out.println("Java Home:" + System.getProperty("java.home"));
System.out.println("JVM 名称:" + System.getProperty("java.vm.name"));
System.out.println("JVM 版本:" + System.getProperty("java.vm.version"));
System.out.println("类路径:" + System.getProperty("java.class.path"));
// 判断 JDK 版本是否满足要求
int majorVersion = Runtime.version().feature();
System.out.println("\n当前主版本号:JDK " + majorVersion);
if (majorVersion >= 17) {
System.out.println("✓ 满足推荐版本要求(JDK 17+)");
} else if (majorVersion >= 11) {
System.out.println("△ 版本可用,但建议升级到 JDK 17+");
} else {
System.out.println("✗ 版本过低,建议升级到 JDK 17+");
}
// 内存信息
Runtime runtime = Runtime.getRuntime();
long maxMemory = runtime.maxMemory() / 1024 / 1024;
long totalMemory = runtime.totalMemory() / 1024 / 1024;
System.out.println("\nJVM 最大内存:" + maxMemory + " MB");
System.out.println("JVM 当前内存:" + totalMemory + " MB");
}
}
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
案例涉及知识点:JDK/JRE/JVM 关系、System.getProperty()、Runtime 类获取 JVM 信息、条件判断。
# 1.2.7 训练题
选择题:JDK、JRE、JVM 三者的包含关系正确的是?
- A. JVM > JRE > JDK B. JDK > JRE > JVM C. JRE > JDK > JVM D. JDK > JVM > JRE
填空题:
javac命令的作用是将.java源文件编译为 ___ 文件;java命令的作用是启动 ___ 来执行字节码。实践题:在命令行中分别执行
java -version和javac -version,观察输出,说明两个命令分别属于 JDK 的哪个组件。思考题:为什么 Java 需要 JVM 这个中间层?如果去掉 JVM,直接把 Java 编译成机器码(像 GraalVM Native Image 那样),会有什么优缺点?
# 1.3 helloWorld
# 1.3.1 第一个案例
让我们看一段简单的代码,可以输出 Hello World。
public class Main {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
2
3
4
5
# 1.3.2 编译运行代码
将代码保存为 Main.java,然后在终端中编译和运行:
$ javac Main.java
$ java Main
Hello World
2
3
# 1.3.3 代码解读
public class Main:定义一个公共类 Main。在 Java 中,每个 .java 文件通常包含一个与文件名同名的公共类。
public static void main(String[] args):这是 Java 程序的入口方法。public 表示公共访问权限,static 表示静态方法(不需要创建对象就能调用),void 表示没有返回值,String[] args 是命令行参数数组。
System.out.println("Hello World");:System.out 是标准输出流对象(类似于 C++ 的 cout),println 表示打印并换行。
对比 C++:
// C++ 的 Hello World
#include <iostream>
using namespace std;
int main() {
cout << "Hello World" << endl;
return 0;
}
2
3
4
5
6
7
Java 的 main 方法必须写在类中,而 C++ 的 main 函数是独立的。Java 不需要 #include 头文件,通过 import 导入包。Java 的 main 方法签名是固定的 public static void main(String[] args)。
# 1.3.4 训练题
改错题:以下代码有几处错误?请找出并改正:
public class hello { public void main(String args) { system.out.println("Hello World") } }1
2
3
4
5实践题:编写一个 Java 程序,在控制台分别输出你的姓名、年龄和爱好,每项信息占一行。
思考题:
main方法的签名public static void main(String[] args)中,每个关键字都不能少。如果把static去掉会怎样?如果把参数改成String args会怎样?请分别尝试并分析原因。
# 1.4 编译Java
# 1.4.0 最简单编译
最简单的编译方式:
$ javac Main.java
编译后会生成 Main.class 字节码文件。运行:
$ java Main
Hello World
2
对比 C++:C++ 编译后直接生成可执行的机器码文件,Java 编译后生成的是字节码文件(.class),需要 JVM 来执行。
C++: main.cpp → g++ 编译 → 可执行文件(机器码)→ 直接运行
Java: Main.java → javac编译 → Main.class(字节码)→ JVM 解释执行
2
# 1.4.1 编译单个文件
javac Main.java
java Main
2
javac:调用 Java 编译器。Main.java:源代码文件。- 编译后生成
Main.class文件。 java Main:使用 JVM 运行,注意不需要加.class后缀。
# 1.4.2 编译多个文件
javac Account.java BankUserManager.java
java BankUserManager
2
如果多个文件有依赖关系,javac 会自动查找并编译依赖的文件。也可以用通配符:
javac *.java
# 1.4.3 指定输出目录
javac -d out src/Account.java src/BankUserManager.java
java -cp out BankUserManager
2
-d out:指定编译输出目录为out。-cp out:指定 classpath(类路径),告诉 JVM 去哪里找.class文件。
# 1.4.4 使用jar打包
# 编译
javac -d out *.java
# 打包成 jar 文件
jar cvfe BankSystem.jar BankUserManager -C out .
# 运行 jar 文件
java -jar BankSystem.jar
2
3
4
5
6
7
8
jar:Java 归档工具,类似于 C++ 中生成静态库.a。cvfe:创建(c)、详细输出(v)、指定入口类(e)。BankSystem.jar:生成的 jar 文件名。BankUserManager:程序入口类。
# 1.4.5 classpath路径
classpath 是 JVM 查找类文件的路径,类似于 C++ 编译时的 -I(头文件路径)和 -L(库路径)。
# 设置 classpath
java -cp .:lib/gson.jar BankUserManager
# 在 classpath 中添加多个路径(macOS/Linux 用冒号分隔,Windows 用分号)
java -cp out:lib/gson.jar:lib/log4j.jar BankUserManager
2
3
4
5
# 1.4.6 综合案例:多文件编译实战
创建一个包含多个文件的小项目,体验编译、打包、运行的完整流程:
文件1:Greeter.java
public class Greeter {
private String name;
public Greeter(String name) {
this.name = name;
}
public String greet() {
return "你好," + name + "!欢迎学习 Java。";
}
}
2
3
4
5
6
7
8
9
10
11
文件2:Main.java
public class Main {
public static void main(String[] args) {
String userName = args.length > 0 ? args[0] : "同学";
Greeter greeter = new Greeter(userName);
System.out.println(greeter.greet());
System.out.println("当前时间:" + new java.util.Date());
}
}
2
3
4
5
6
7
8
编译和运行步骤:
# 1. 编译所有文件
javac -d out Greeter.java Main.java
# 2. 运行(指定 classpath)
java -cp out Main 张三
# 3. 打包成 jar
jar cvfe app.jar Main -C out .
# 4. 运行 jar
java -jar app.jar 李四
2
3
4
5
6
7
8
9
10
11
案例涉及知识点:多文件编译、-d 输出目录、命令行参数 args、-cp classpath、jar 打包。
# 1.4.7 训练题
实践题:创建两个 Java 文件
Animal.java和Main.java,Main中使用Animal类。分别用以下方式编译运行:- 直接
javac *.java && java Main - 使用
-d out指定输出目录后运行
- 直接
填空题:将多个
.class文件打包为.jar文件的命令是 ___;运行.jar文件的命令是 ___。思考题:Java 编译后生成的字节码文件和 C++ 编译后生成的可执行文件有什么本质区别?在实际部署时,分别有什么优势和劣势?
# 1.5 多种注释使用
在 Java 中,注释 是用于解释代码的文本,编译器会忽略注释内容。注释对于提高代码的可读性和维护性非常重要。
提示:编译器在编译代码时,会忽略注释的内容
# 1.5.1 单行注释
单行注释:// 描述信息
通常放在一行代码的上方,或者一条语句的末尾,对该行代码说明
public class Main {
public static void main(String[] args) {
// 输出 Hello World
System.out.println("Hello World"); // 这是行尾注释
}
}
2
3
4
5
6
# 1.5.2 多行注释
多行注释:/* 描述信息 */
通常放在一段代码的上方,对该段代码做整体说明
/*
这是一个简单的 Java 程序
用于输出 Hello World
*/
public class Main {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
2
3
4
5
6
7
8
9
# 1.5.3 文档注释
Java 特有的 文档注释:/** 描述信息 */
配合 javadoc 工具可以生成 API 文档。文档注释可以包含标签(如 @param、@return、@author 等)。
/**
* 银行账户类
* @author yangchong
* @version 1.0
*/
public class Account {
/**
* 存款方法
* @param amount 存款金额,必须大于0
* @return 存款后的余额
*/
public double deposit(double amount) {
balance += amount;
return balance;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
生成文档:
javadoc -d doc Account.java
对比 C++:C++ 使用 Doxygen 等外部工具生成文档,而 Java 内置了 javadoc 工具,文档注释是语言标准的一部分。
# 1.5.4 综合案例:API文档生成器
编写一个包含完整文档注释的类,然后使用 javadoc 生成 HTML 文档:
/**
* 温度转换工具类
* <p>支持摄氏度和华氏度之间的互相转换</p>
*
* @author yangchong
* @version 1.0
* @since JDK 11
*/
public class TemperatureConverter {
/** 绝对零度(摄氏度) */
public static final double ABSOLUTE_ZERO_CELSIUS = -273.15;
/**
* 将摄氏度转换为华氏度
*
* @param celsius 摄氏温度值
* @return 对应的华氏温度值
* @throws IllegalArgumentException 如果温度低于绝对零度
*/
public static double toFahrenheit(double celsius) {
if (celsius < ABSOLUTE_ZERO_CELSIUS) {
throw new IllegalArgumentException("温度不能低于绝对零度");
}
return celsius * 9.0 / 5.0 + 32;
}
/**
* 将华氏度转换为摄氏度
*
* @param fahrenheit 华氏温度值
* @return 对应的摄氏温度值
*/
public static double toCelsius(double fahrenheit) {
return (fahrenheit - 32) * 5.0 / 9.0;
}
// 单行注释:主方法演示
public static void main(String[] args) {
/* 多行注释:
测试几组常见温度的转换 */
double[] testTemps = {0, 100, 37, -40};
for (double c : testTemps) {
System.out.printf("%.1f°C = %.1f°F%n", c, toFahrenheit(c));
}
}
}
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
生成文档命令:javadoc -d doc -encoding UTF-8 TemperatureConverter.java
案例涉及知识点:单行注释、多行注释、文档注释(@author、@version、@param、@return、@throws、@since)、javadoc 工具。
# 1.5.5 训练题
实践题:为以下类添加完整的文档注释(包括类注释和方法注释),然后用
javadoc命令生成 HTML 文档:public class Calculator { public int add(int a, int b) { return a + b; } public double divide(double a, double b) { if (b == 0) throw new ArithmeticException("除数不能为0"); return a / b; } }1
2
3
4
5
6
7
8
9判断题:多行注释可以嵌套使用,即
/* /* 嵌套 */ */是合法的。( )思考题:在实际开发中,注释过多和注释过少都不好。请思考什么样的代码需要注释,什么样的代码应该通过良好的命名来"自解释"?
# 1.6 包(Package)
包(Package) 是 Java 中用于组织类的机制,类似于 C++ 的命名空间(namespace),用于避免命名冲突,并提供访问控制。
包的底层原理:Java 的包在编译后对应文件系统的目录结构。package com.bank.model; 声明的类编译后的 .class 文件必须存放在 com/bank/model/ 目录下。JVM 的类加载器通过 classpath + 包名路径来定位和加载类文件。包名与目录结构的一一对应关系是 Java 类加载机制的基础。
# 1.6.1 包的概念
遇到问题:一个大型项目由多名程序员共同开发,不可避免地会出现类名冲突。例如,你写了一个 Account 类,别人也写了一个 Account 类。
解决办法:通过包来区分不同的类。本质上,包就是类的"分组",一个包对应文件系统中的一个目录。
作用:防止命名冲突,组织和管理类。
# 1.6.2 定义包
使用 package 关键字在源文件的第一行声明包名:
package com.bank.model;
public class Account {
private String name;
private double balance;
}
2
3
4
5
6
# 1.6.3 导入包
使用 import 关键字导入其他包中的类:
// 导入单个类
import com.bank.model.Account;
// 导入包下的所有类
import com.bank.model.*;
// 使用完全限定名(不需要导入)
com.bank.model.Account account = new com.bank.model.Account();
2
3
4
5
6
7
8
对比 C++:
// C++ 的命名空间
using namespace std; // 类似 Java 的 import java.util.*;
using std::cout; // 类似 Java 的 import java.util.ArrayList;
std::cout << "Hello"; // 类似 Java 的 java.util.ArrayList list;
2
3
4
# 1.6.4 包的命名规范
包名通常使用公司域名的倒序,全部小写:
com.company.project.module
// 例如
com.bank.model // 数据模型
com.bank.service // 业务逻辑
com.bank.util // 工具类
2
3
4
5
# 1.6.5 常用内置包
| 包名 | 说明 |
|---|---|
java.lang | 核心类库(String、System、Math 等),自动导入 |
java.util | 工具类(集合框架、日期、Random 等) |
java.io | 输入输出流 |
java.net | 网络编程 |
java.sql | 数据库操作 |
java.math | 大数运算(BigDecimal、BigInteger) |
# 1.6.6 静态导入
Java 5 引入了静态导入,可以直接导入类的静态成员:
import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
public class Main {
public static void main(String[] args) {
double r = 5.0;
double area = PI * r * r; // 直接使用 PI,不需要 Math.PI
double result = sqrt(25); // 直接使用 sqrt,不需要 Math.sqrt
System.out.println("area = " + area);
System.out.println("sqrt(25) = " + result);
}
}
2
3
4
5
6
7
8
9
10
11
12
# 1.6.7 综合练习题
- 使用
package关键字声明包名,包名通常使用公司域名倒序。 - 使用
import关键字导入其他包的类,使用import static导入静态成员。 java.lang包是自动导入的,不需要手动import。
package com.bank;
import com.bank.model.Account;
import java.util.ArrayList;
import static java.lang.System.out;
public class Main {
public static void main(String[] args) {
// 使用导入的类
Account account = new Account("张三", 1000);
ArrayList<Account> accounts = new ArrayList<>();
accounts.add(account);
// 使用静态导入
out.println("账户列表:");
for (Account acc : accounts) {
out.println(acc.getName());
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1.7 修饰符
在 Java 中,修饰符 是用于修饰类、方法、变量等的关键字,用于改变它们的属性和行为。
底层原理:访问控制修饰符的信息存储在 .class 文件的访问标志位(access_flags)中。JVM 在执行字节码时通过检查这些标志位来决定是否允许访问某个类、方法或字段。public 对应标志 0x0001,private 对应 0x0002,protected 对应 0x0004,static 对应 0x0008。如果违反了访问权限,JVM 会抛出 IllegalAccessError。
# 1.7.1 访问控制修饰符
Java 提供了四种访问级别:
| 修饰符 | 当前类 | 同一包 | 子类 | 其他包 |
|---|---|---|---|---|
public | ✓ | ✓ | ✓ | ✓ |
protected | ✓ | ✓ | ✓ | ✗ |
| 默认(无修饰符) | ✓ | ✓ | ✗ | ✗ |
private | ✓ | ✗ | ✗ | ✗ |
对比 C++:C++ 只有 public、protected、private 三种,Java 多了一个"默认"(包访问权限)。
示例:
public class Account {
public String name; // 所有地方都能访问
protected double balance; // 同包和子类可以访问
int id; // 默认,同包可以访问
private String password; // 只有当前类可以访问
}
2
3
4
5
6
# 1.7.2 非访问修饰符
| 修饰符 | 作用 |
|---|---|
static | 静态成员,属于类而不是对象 |
final | 不可修改(变量)、不可重写(方法)、不可继承(类) |
abstract | 抽象类或抽象方法 |
synchronized | 同步方法,保证线程安全 |
volatile | 可见性保证,禁止指令重排序 |
transient | 序列化时忽略该字段 |
native | 调用本地方法(C/C++ 实现) |
# 1.7.3 static修饰符
static 修饰的成员属于类本身,不属于某个具体的对象。
public class Account {
// 静态变量:所有对象共享
static int totalCount = 0;
// 实例变量:每个对象各自拥有
String name;
public Account(String name) {
this.name = name;
totalCount++; // 每创建一个对象,计数加1
}
// 静态方法:通过类名直接调用
public static int getTotalCount() {
return totalCount;
}
}
// 使用
Account a1 = new Account("张三");
Account a2 = new Account("李四");
System.out.println(Account.getTotalCount()); // 2,通过类名调用
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
对比 C++:C++ 也有 static 关键字,用法基本一致。
# 1.7.4 final修饰符
final 有三种用途:
// 1. final 变量:常量,不可修改
final double PI = 3.14159;
// PI = 3.0; // 编译错误
// 2. final 方法:不可被子类重写
public class Account {
public final String getAccountType() {
return "普通账户";
}
}
// 3. final 类:不可被继承
public final class String {
// String 类是 final 的,不能被继承
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
对比 C++:C++ 中 const 类似于 Java 的 final 变量,C++11 的 final 关键字功能与 Java 的 final 方法/类一致。
# 1.7.5 abstract修饰符
abstract 用于定义抽象类和抽象方法:
// 抽象类不能被实例化
public abstract class Shape {
// 抽象方法没有方法体,子类必须实现
public abstract double area();
// 抽象类可以有普通方法
public void describe() {
System.out.println("这是一个形状");
}
}
public class Circle extends Shape {
private double radius;
@Override
public double area() {
return Math.PI * radius * radius;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
对比 C++:C++ 通过纯虚函数(virtual void func() = 0;)实现抽象类,Java 用 abstract 关键字更加直观。
# 1.7.6 修饰符总结
| 修饰符 | 类 | 方法 | 变量 |
|---|---|---|---|
public | ✓ | ✓ | ✓ |
protected | ✗ | ✓ | ✓ |
private | ✗(内部类可以) | ✓ | ✓ |
static | ✗(内部类可以) | ✓ | ✓ |
final | ✓ | ✓ | ✓ |
abstract | ✓ | ✓ | ✗ |
# 1.7.7 综合案例:权限控制模拟
通过一个完整示例展示各种修饰符的实际用途:
public class AccessControlDemo {
// static final:全局常量
public static final String SYSTEM_NAME = "用户管理系统";
// static:共享计数器
private static int userCount = 0;
// private:核心数据,外部不可直接访问
private String username;
private String password;
// protected:子类可访问
protected String role;
// public 构造方法
public AccessControlDemo(String username, String password) {
this.username = username;
this.password = password;
this.role = "普通用户";
userCount++;
}
// public:对外暴露的接口
public String getUsername() {
return username;
}
// private:内部校验逻辑
private boolean validatePassword(String input) {
return this.password.equals(input);
}
// public:通过方法间接使用私有逻辑
public boolean login(String inputPassword) {
boolean success = validatePassword(inputPassword);
System.out.println(username + " 登录" + (success ? "成功" : "失败"));
return success;
}
// final:不允许子类重写
public final void showInfo() {
System.out.printf("[%s] 用户:%s,角色:%s%n", SYSTEM_NAME, username, role);
}
// static:通过类名调用
public static int getUserCount() {
return userCount;
}
public static void main(String[] args) {
AccessControlDemo user1 = new AccessControlDemo("张三", "123456");
AccessControlDemo user2 = new AccessControlDemo("李四", "abcdef");
user1.login("123456"); // 张三 登录成功
user2.login("wrong"); // 李四 登录失败
user1.showInfo();
System.out.println("注册用户总数:" + AccessControlDemo.getUserCount());
}
}
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
案例涉及知识点:public/private/protected/默认修饰符、static 变量和方法、final 常量和方法、封装的实际应用。
# 1.7.8 训练题
选择题:以下哪个修饰符组合是合法的?
- A.
public privateB.static finalC.abstract finalD.private protected
- A.
填空题:
protected修饰的成员可以被 、 和 ___ 访问,但不能被 ___ 访问。实践题:创建一个
Person类,要求:name属性为private,通过 getter/setter 访问age属性为protected- 提供一个
static方法getPersonCount()返回创建过的 Person 对象总数 - 提供一个
final方法getIdCard()不允许子类重写
思考题:Java 有四种访问级别(public、protected、默认、private),而 C++ 只有三种。Java 多出的"默认(包访问权限)"在实际项目中有什么用途?
# 1.8 标识符
# 1.8.1 标识符规则
Java 标识符是用来标识变量、方法、类、包等的名称。规则:
- 标识符可以由字母、数字、下划线(
_)和美元符号($)组成 - 第一个字符不能是数字
- 标识符不能是 Java 关键字
- 标识符区分大小写
建议:给标识符命名时,争取做到见名知意的效果,方便自己和他人的阅读
# 1.8.2 命名规范
Java 有一套广泛遵循的命名规范:
| 类型 | 命名规范 | 示例 |
|---|---|---|
| 类名 | 大驼峰命名法 | BankAccount、UserManager |
| 方法名 | 小驼峰命名法 | getBalance()、deposit() |
| 变量名 | 小驼峰命名法 | accountName、totalBalance |
| 常量名 | 全大写,下划线分隔 | MAX_SIZE、DEFAULT_NAME |
| 包名 | 全小写 | com.bank.model |
# 1.8.3 综合案例:命名规范检查器
编写一个简单的命名规范检查工具,验证标识符是否符合 Java 命名规范:
public class NamingConventionChecker {
// 常量命名:全大写+下划线
public static final String CLASS_PATTERN = "大驼峰(如 BankAccount)";
public static final String METHOD_PATTERN = "小驼峰(如 getBalance)";
public static final String CONSTANT_PATTERN = "全大写下划线(如 MAX_SIZE)";
public static String checkClassName(String name) {
if (name == null || name.isEmpty()) return "✗ 类名不能为空";
if (!Character.isUpperCase(name.charAt(0))) return "✗ 类名应以大写字母开头";
if (name.contains("_")) return "✗ 类名不应包含下划线,应用大驼峰";
return "✓ 类名合规:" + name;
}
public static String checkVariableName(String name) {
if (name == null || name.isEmpty()) return "✗ 变量名不能为空";
if (Character.isUpperCase(name.charAt(0))) return "✗ 变量名应以小写字母开头";
if (name.equals("l") || name.equals("O")) return "△ 单字母变量易与数字混淆";
return "✓ 变量名合规:" + name;
}
public static void main(String[] args) {
System.out.println("=== 类名检查 ===");
System.out.println(checkClassName("BankAccount"));
System.out.println(checkClassName("bankAccount"));
System.out.println(checkClassName("bank_account"));
System.out.println("\n=== 变量名检查 ===");
System.out.println(checkVariableName("totalBalance"));
System.out.println(checkVariableName("TotalBalance"));
System.out.println(checkVariableName("l"));
}
}
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
案例涉及知识点:标识符规则、Java 命名规范(大驼峰、小驼峰、全大写下划线)、Character 类判断字符属性。
# 1.8.4 训练题
判断题:以下哪些是合法的 Java 标识符?
- A.
_countB.2ndNameC.$priceD.classE.myVarF.user-name
- A.
改错题:以下变量命名有什么不规范之处?请按 Java 命名规范改正:
String Name = "张三"; // 变量 int MAX_VALUE = 100; // 变量 class account_manager { } // 类 void GetBalance() { } // 方法1
2
3
4思考题:为什么 Java 推荐使用有意义的命名而不是
a、b、x这样的短名称?在什么情况下短名称是可以接受的?
# 1.9 关键字
Java 中的关键字是语言保留的标识符,具有特定的含义和用途,不能用作变量名、方法名或其他用户定义的标识符。
作用:关键字是 Java 中预先保留的单词
- 在定义变量或者常量时候,不要用关键字
Java 关键字如下(共50个):
| abstract | assert | boolean | break | byte |
|---|---|---|---|---|
| case | catch | char | class | const |
| continue | default | do | double | else |
| enum | extends | final | finally | float |
| for | goto | if | implements | import |
| instanceof | int | interface | long | native |
| new | package | private | protected | public |
| return | short | static | strictfp | super |
| switch | synchronized | this | throw | throws |
| transient | try | void | volatile | while |
提示:在给变量或者常量起名称时候,不要用 Java 的关键字,否则会产生编译错误。
# 1.9.1 数据类型关键字
| 关键字 | 含义 |
|---|---|
int | 整型(4字节) |
float | 浮点型(4字节) |
double | 双精度浮点型(8字节) |
char | 字符型(2字节) |
boolean | 布尔型(true 或 false) |
void | 无类型 |
long | 长整型(8字节) |
short | 短整型(2字节) |
byte | 字节型(1字节) |
# 1.9.2 控制语句关键字
| 关键字 | 含义 |
|---|---|
if | 条件语句 |
else | 条件语句的分支 |
switch | 多分支选择语句 |
case | switch 的分支 |
default | switch 的默认分支 |
for | 循环语句 |
while | 循环语句 |
do | 循环语句 |
break | 跳出循环或 switch |
continue | 跳过本次循环 |
return | 从方法返回 |
# 1.9.3 类和对象关键字
| 关键字 | 含义 |
|---|---|
class | 定义类 |
interface | 定义接口 |
enum | 定义枚举 |
extends | 类继承 |
implements | 实现接口 |
new | 创建对象 |
this | 当前对象的引用 |
super | 父类的引用 |
instanceof | 判断对象类型 |
abstract | 抽象类或方法 |
final | 不可修改/不可继承/不可重写 |
static | 静态成员 |
# 1.9.4 异常处理关键字
| 关键字 | 含义 |
|---|---|
try | 尝试执行一段代码 |
catch | 捕获异常 |
finally | 无论是否异常都执行 |
throw | 抛出异常 |
throws | 声明方法可能抛出的异常 |
# 1.9.5 包相关关键字
| 关键字 | 含义 |
|---|---|
package | 声明包 |
import | 导入包 |
# 1.9.6 其他关键字
| 关键字 | 含义 |
|---|---|
synchronized | 同步,保证线程安全 |
volatile | 可见性保证 |
transient | 序列化时忽略 |
native | 本地方法(C/C++ 实现) |
assert | 断言 |
strictfp | 严格浮点运算 |
| strictfp | 严格浮点运算 |
# 1.9.7 综合案例:关键字分类查询工具
编写一个工具,将 Java 关键字按用途分类,支持查询和统计:
public class KeywordLookup {
static final String[] DATA_TYPES = {"int", "float", "double", "char", "boolean", "void", "long", "short", "byte"};
static final String[] CONTROL = {"if", "else", "switch", "case", "default", "for", "while", "do", "break", "continue", "return"};
static final String[] OOP = {"class", "interface", "enum", "extends", "implements", "new", "this", "super", "instanceof", "abstract", "final", "static"};
static final String[] EXCEPTION = {"try", "catch", "finally", "throw", "throws"};
public static String findCategory(String keyword) {
for (String k : DATA_TYPES) if (k.equals(keyword)) return "数据类型关键字";
for (String k : CONTROL) if (k.equals(keyword)) return "控制语句关键字";
for (String k : OOP) if (k.equals(keyword)) return "类和对象关键字";
for (String k : EXCEPTION) if (k.equals(keyword)) return "异常处理关键字";
return "其他关键字或非关键字";
}
public static void main(String[] args) {
// 查询关键字分类
String[] testWords = {"int", "for", "class", "try", "goto", "hello"};
for (String word : testWords) {
System.out.printf(" %-12s → %s%n", word, findCategory(word));
}
// 统计各类关键字数量
System.out.println("\n=== 关键字统计 ===");
System.out.println("数据类型:" + DATA_TYPES.length + " 个");
System.out.println("控制语句:" + CONTROL.length + " 个");
System.out.println("类和对象:" + OOP.length + " 个");
System.out.println("异常处理:" + EXCEPTION.length + " 个");
}
}
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
案例涉及知识点:关键字分类、数组、字符串比较 equals()、static final 常量数组、循环遍历查找。
# 1.9.8 训练题
选择题:以下哪个可以作为 Java 变量名?
- A.
intB.IntegerC.gotoD.nullE._null
- A.
分类练习:将以下关键字归入正确的类别(数据类型/控制语句/类和对象/异常处理):
try、int、extends、while、catch、boolean、new、if、abstract、finally思考题:
goto和const是 Java 的保留关键字但没有实际功能。请查阅资料,说明 Java 为什么保留了它们?Java 中如何实现goto的功能(如跳出多层循环)?