Java 基础语法

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 定义了一个公开的类,类名叫 Mainpublic static void main(String[] args) 是程序的入口方法,Java 程序运行时会自动找到并执行这个方法。

现阶段你不用纠结 publicstaticvoid 这些关键字是什么意思,后面讲面向对象的时候会详细解释。现在只需要知道:所有代码都写在 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;     // 编译器推断为 int

var 只是语法糖,类型在编译时就确定了,不是动态类型。

类型转换

小类型可以自动转换为大类型(不丢精度),反过来需要强制转换:

特别注意整数除法:1 / 2 的结果是 0 而不是 0.5,因为两个 int 相除结果还是 int,小数部分直接丢掉。这在算法题中是个常见的坑。

运算符

算术运算符

取余运算符 % 在算法题中非常常用,比如判断奇偶(n % 2 == 0)、循环数组索引(i % n)等。

比较与逻辑运算符

比较运算符返回 boolean 值:==(等于)、!=(不等于)、<><=>=

逻辑运算符用于组合布尔表达式:&&(与)、||(或)、!(非)。

三元运算符

条件 ? 值1 : 值2if-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-whilewhile 的区别是: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 语句在做什么,以及标准库都提供了哪些好用的工具类。