Skip to content

基础语法与程序结构 ​

学习目标 ​

  • 看懂一个 Java 源文件中的包、导入、类、字段、方法和语句之间的层次。
  • 会声明局部变量和常量,理解标识符、作用域、初始化与 var 的边界。
  • 能用 System.out 输出信息,用 Scanner 读取简单输入,并知道输入失败时如何处理。

核心知识点 ​

专业术语 ​

  • 语句(statement):完成一次动作的代码,通常以分号结束,例如赋值、方法调用和 return。
  • 表达式(expression):能够产生一个值的代码,例如 price * count 或 name.trim()。
  • 标识符(identifier):变量、方法、类等名称;不能使用关键字,通常用 lowerCamelCase 命名变量和方法。
  • 作用域(scope):名称可被直接使用的代码范围;局部变量离开大括号后就不可见。
  • 常量(constant):使用 final 绑定后不能再次赋值的变量;对象本身是否可变要另行判断。
  • 类型推断(type inference):var 让编译器从初始化表达式推断局部变量的静态类型,不会变成动态类型。

白话解释与边界 ​

程序骨架:package、import 与 class ​

一个源文件可以看成“声明 + 执行”的树:package 声明命名空间,import 提供类型简写,顶层 class 包含字段和方法,方法内部再由局部变量、表达式和语句组成。大括号既划分结构,也划分局部变量的作用域。

变量与 final 常量 ​

变量声明必须有类型和名称;局部变量在读取前必须完成明确赋值。final 只禁止变量再次指向另一个值:final StringBuilder 仍可修改对象内容,但不能把变量改指向新的 StringBuilder。常量通常使用 static final,并用大写下划线命名。

var 类型推断 ​

var 只能用于有初始化表达式的局部变量和传统 for 循环变量,不能用作字段、方法参数、返回类型或没有初值的声明。公开 API 通常直接写出类型,调用者才能从方法签名看懂约定。

print、println 与 printf 输出 ​

输出时,print 不换行,println 换行,printf 按格式输出;字符串拼接从左到右计算,"总价=" + 3 * 2 会先算乘法。

Scanner 输入 ​

Scanner 适合教学和简单命令行输入,nextInt() 遇到非整数会抛出 InputMismatchException;真实程序应明确校验输入或用 nextLine() 后自行解析。

常用用法 ​

final 与 static final:表达稳定值 ​

final 变量只能赋值一次,static final 常用于全类共享的常量;引用不可变不等于引用指向的对象不可变。

java
// 语义:final 变量只能赋值一次,static final 常用于全类共享的常量。
// 初始状态:MAX_RETRY 初始为 3;name 初始为 "Java"。
public class ConstantDemo {
// 作用:final 变量只能赋值一次,static final 常用于全类共享的常量;引用不可变不等于引用指向的对象不可变。
    private static final int MAX_RETRY = 3;
// 初始状态:MAX_RETRY 的初始值为 3。

    public static void main(String[] args) {
        final String name = "Java";
        System.out.println(name + ":" + MAX_RETRY);
        // 输出:Java:3
    }
}

var:让局部变量从初值推断类型 ​

var 只能用于有初值的局部变量;公开字段、参数和返回类型应保留明确类型。

java
public class VarDemo {
// 作用:var 只能用于有初值的局部变量;公开字段、参数和返回类型应保留明确类型。
    public static void main(String[] args) {
        var message = "Java";
        // 初始状态:message 当前为 "Java"。
        // 作用:var 只能用于有初值的局部变量。
        System.out.println(message.toUpperCase());
        // 输出:JAVA
    }
}

不常用但需要知道 ​

Scanner:读取简单命令行输入 ​

教学场景可用 Scanner 读取输入;服务端代码通常会使用明确的参数解析和校验层。

java
import java.util.Scanner;

public class ScannerDemo {
    public static void main(String[] args) {
        try (Scanner scanner = new Scanner("20")) {
// 初始状态:new Scanner("20") 提供文本 20,scanner.nextInt() 将读取整数 20。
        // 作用:通过 Scanner 读取简单命令行输入。
            System.out.println(scanner.nextInt());
            // 输出:20
        }
    }
}

printf:按格式输出文本 ​

printf 适合命令行展示;日志和协议文本应使用项目统一的格式化方式。

java
public class PrintfDemo {
    public static void main(String[] args) {
        System.out.printf("score=%d%n", 95);
// 输出:score=95
        // 作用:通过 printf 按格式输出文本。
    }
}

简单案例 ​

下面的例子展示类的骨架、常量、局部变量、var、输出和一次简单输入。运行时输入一个名字即可;没有输入时使用默认值。

java
import java.util.Scanner;

public class SyntaxDemo {
    private static final String GREETING = "你好";

    public static void main(String[] args) {
        final int defaultAge = 18;
        String name;
        int age = defaultAge;

        try (Scanner scanner = new Scanner(System.in)) {
            System.out.print("姓名(直接回车使用 Java):");
            // 输出:姓名(直接回车使用 Java):
            String line = scanner.nextLine().trim();
            name = line.isEmpty() ? "Java" : line;
        }

        var message = GREETING + "," + name;
        System.out.println(message);
        // 输出:你好,Java
        System.out.printf("年龄=%d,常量=%s%n", age, GREETING);
        // 输出:年龄=18,常量=你好
    }
}

GREETING 是类级常量,name 和 age 是方法内局部变量,message 的静态类型由编译器推断为 String。try-with-resources 会在读取结束后关闭 Scanner;从 System.in 读取时应避免在同一输入流上随意创建多个 Scanner。

易混点 ​

  • 分号结束的是语句,不是每个大括号;类、方法和控制结构的大括号表达层级。
  • final 变量不能重新赋值,但引用指向的对象是否可变取决于对象类型。
  • var 不是动态类型,必须有初值,编译器会在编译期确定唯一类型。
  • print、println 和 printf 都是输出方法;printf 的格式符必须和参数类型匹配。
  • nextInt() 会留下换行符,随后调用 nextLine() 可能先读到空行;混用时要主动处理剩余换行。

课后小问 ​

  1. 为什么下面的声明不能通过编译:var count;? 答案:因为 var 必须从同一条声明中的初始化表达式推断类型。 解析:没有初值时编译器不知道 count 应该是 int、String 还是其他类型;如果暂时不赋值,应明确写出类型并在读取前完成赋值。

  2. final List<String> names 能不能调用 names.add("Ada")? 答案:可以,final 禁止的是变量重新赋值,不是自动冻结列表内容。 解析:变量保存的是列表引用,add 修改引用指向的列表对象;但 names = new ArrayList<>() 会被编译器拒绝。若需要不可变内容,应使用不可变集合工厂或复制后暴露只读视图。

  3. 为什么 System.out.println("总价=" + 3 + 2) 输出的是 总价=32? 答案:字符串拼接从左到右进行,"总价=" + 3 先得到字符串,再与 2 拼接。 解析:要先做数值加法,应加括号写成 "总价=" + (3 + 2);括号同时表达意图,也避免被运算符优先级误导。

本节小结 ​

  • Java 程序由包、导入、类型、方法和语句组成,大括号同时划分结构和局部作用域。
  • 局部变量必须先初始化再读取,final 表示不能重新赋值,常量通常写成 static final。
  • var 只做局部变量的编译期类型推断,不会改变 Java 的静态类型规则。
  • print、println、printf 和 Scanner 覆盖了入门阶段最常见的控制台输入输出。

快速回顾 ​

  • 能指出一个类、方法、局部变量和语句分别位于程序的哪一层。
  • 能判断 final、var 和明确类型声明各自适用的场景。
  • 能区分表达式与语句,并解释大括号对作用域的影响。
  • 能说明 nextInt() 与 nextLine() 混用时的换行边界。

继续阅读 ​