Java 是一门面向对象的编程语言,它最大的特点是「一次编写,到处运行」:Java 代码编译成字节码后,可以在任何安装了 Java 虚拟机(JVM)的平台上运行,不用关心底层是 Windows、Mac 还是 Linux。
Java 的语法和 C/C++ 比较像,但去掉了指针、手动内存管理这些容易出错的特性,新手上手会比 C++ 舒服很多。同时 Java 的标准库非常丰富,常用的数据结构都给你准备好了,拿来就能用。
不过说实话,随着技术的演进,尤其是容器化技术(Docker)的成熟,「一次编写,到处运行」的优势已经不那么突出了,因为现在任何语言打成容器镜像都能到处运行。
曾经作为核心竞争力的 JVM 反而成了负担:一个简单的 helloworld 程序也需要几百 MB 内存来启动 JVM,启动速度也比不上 Go、Rust 这些直接编译成机器码的语言。再加上 Java 的语法比较啰嗦,所以近些年,Java 的热度确实在被其他语言分走。
不过,Java 本身也在不断进步,企业招聘需求也一直很大,所以掌握 Java 也是一个非常好的选择:语法严谨、标准库完善、大量算法教程和竞赛题目都提供 Java 解法。
下面我们就开始学习 Java 的基础语法。
Hello World 与程序结构
先看一个最简单的 Java 程序:
虽然只有一行有效逻辑,但 Java 要求你必须把代码写在一个类(class)里面,而且程序的入口是 main 方法。这是 Java 的规矩,记住就行。
拆解一下这个结构:
public class Main { // 定义一个类,类名为 Main
public static void main(String[] args) { // 程序入口
// 你的代码写在这里
}
}public class Main 定义了一个公开的类,类名叫 Main。public static void main(String[] args) 是程序的入口方法,Java 程序运行时会自动找到并执行这个方法。
现阶段你不用纠结 public、static、void 这些关键字是什么意思,后面讲面向对象的时候会详细解释。现在只需要知道:所有代码都写在 main 方法的花括号 {} 里就行。
关于 Java 中「类」的规矩
和 Python、JavaScript 这些语言不同,Java 中「类」不只是一个面向对象的概念,而是代码组织的基本单位。Java 不允许你在类外面写任何代码,所有的变量、方法都必须放在某个类里面。
Java 还有几条硬性规则,初学者容易踩坑:
一个文件只能有一个 public 类,而且文件名必须和这个类名一致。比如 public class Main 必须写在 Main.java 文件里。不过在本站的在线编辑器中你不需要关心文件名,直接写代码就行。
main 方法是程序的唯一入口,签名必须是 public static void main(String[] args),一个字都不能改。Java 程序启动时会去找这个方法来执行,找不到就报错。
一个文件里可以有多个类,但只有一个能是 public 的。其他类不加 public 修饰符就行:
// Main.java
public class Main {
public static void main(String[] args) {
Helper h = new Helper();
h.sayHi();
}
}
// 同一个文件中的非 public 类
class Helper {
void sayHi() {
System.out.println("Hi!");
}
}这些规则看起来比较啰嗦,这也是 Java 一直被人吐槽的地方。但好处是代码结构非常统一,看到任何 Java 项目都能很快找到入口在哪。
标准输出
System.out.println 用于在控制台打印一行内容。System.out.print 功能类似,但不会自动换行。
其中 printf 是格式化输出,%d 表示整数,%f 表示浮点数(%.2f 表示保留两位小数),%s 表示字符串,\n 表示换行。如果你学过 C 语言,会发现用法一模一样。
读取输入
有输出就有输入。Java 用 Scanner 类来读取用户的输入。Scanner 不是 Java 内置可以直接使用的类,需要用 import 语句引入,后面会专门讲 import 机制,现在只需要知道用 Scanner 之前要加这行就行:
Scanner 的常用方法就这几个:
| 方法 | 说明 |
|---|---|
next() | 读取一个字符串(遇到空格或换行就停) |
nextLine() | 读取一整行 |
nextInt() | 读取一个整数 |
nextDouble() | 读取一个浮点数 |
hasNext() | 判断是否还有输入(循环读取时常用) |
上面的示例中,左下角的 stdin 区域就是模拟的用户输入,你可以修改输入内容再运行试试。
变量与数据类型
基本类型
Java 的基本数据类型有 8 种,最常用的是以下几种:
| 类型 | 说明 | 示例 |
|---|---|---|
int | 整数(32位) | int a = 10; |
long | 长整数(64位) | long b = 100000000000L; |
double | 浮点数(小数) | double c = 3.14; |
boolean | 布尔值 | boolean d = true; |
char | 单个字符 | char e = 'A'; |
几个注意点:
long 类型的字面量要加 L 后缀(如 9999999999L),否则编译器会把它当成 int,超出 int 范围就会报错。
char 用单引号 'A',String(字符串)用双引号 "Hello",这两个不能搞混。
变量声明
Java 是静态类型语言,变量必须先声明类型才能使用:
// 先声明,后赋值
int x;
x = 10;
// 声明的同时赋值
int y = 20;
// 一行声明多个同类型变量
int a = 1, b = 2, c = 3;Java 10 以后可以用 var 让编译器自动推断类型:
var name = "Java"; // 编译器推断为 String
var count = 100; // 编译器推断为 intvar 只是语法糖,类型在编译时就确定了,不是动态类型。
类型转换
小类型可以自动转换为大类型(不丢精度),反过来需要强制转换:
特别注意整数除法:1 / 2 的结果是 0 而不是 0.5,因为两个 int 相除结果还是 int,小数部分直接丢掉。这在算法题中是个常见的坑。
运算符
算术运算符
取余运算符 % 在算法题中非常常用,比如判断奇偶(n % 2 == 0)、循环数组索引(i % n)等。
比较与逻辑运算符
比较运算符返回 boolean 值:==(等于)、!=(不等于)、<、>、<=、>=。
逻辑运算符用于组合布尔表达式:&&(与)、||(或)、!(非)。
三元运算符
条件 ? 值1 : 值2 是 if-else 的简写形式,条件为 true 返回值1,否则返回值2:
int a = 10, b = 20;
int max = (a > b) ? a : b; // max = 20位运算
位运算在处理二进制相关问题时非常高效,在算法题中可能会遇到。详细的位运算原理可以参考 常用的位操作,这里了解一下基本用法就可以了:
控制流
条件判断 if / else
for 循环
for 循环是最常用的循环,由三部分组成:for (初始化; 条件; 更新)。
while 循环
while 循环适合循环次数不确定的场景:
do-while 和 while 的区别是:do-while 先执行一次再判断条件,所以循环体至少会执行一次。实际中 do-while 用得很少,了解一下就行。
for-each 遍历
遍历数组或集合时,for-each 比普通 for 循环更简洁:
for-each 的限制是拿不到索引 i,也不能在遍历时修改元素。如果需要索引,还是用普通 for 循环。
break 和 continue
break 跳出整个循环,continue 跳过当前这轮、进入下一轮:
switch 语句
switch 适合对一个变量做多个值的判断,比一长串 if-else 更清晰:
注意每个 case 后面要加 break,否则会"穿透"到下一个 case 继续执行。
Java 14 引入了更简洁的 switch 写法,用箭头 -> 代替 case: break:
新语法不需要 break,也不会穿透。使用时看个人喜好吧。
小结
这篇介绍了 Java 的基础语法:程序结构、数据类型、运算符和控制流。这些是所有 Java 代码的基石。
下一篇我们来讲讲 Java 的 包与导入 机制,看看 import 语句在做什么,以及标准库都提供了哪些好用的工具类。