类的基本结构

public class Person {
    // 字段
    private String name;
    private int age;

    // 构造函数
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 方法
    public void greet() {
        System.out.println("Hi, I'm " + name);
    }

    // getter / setter
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

// 用
var p = new Person("Alice", 30);
p.greet();

一文件多类

// Person.java
public class Person { ... }    // public class 名字必须 = 文件名

class Helper { ... }            // 包私有的辅助类,能在同文件

一个 public class 一文件。其他非 public 类可以同文件(少见)。

构造函数

public class Box {
    private int width, height;

    // 默认构造
    public Box() {
        width = 1; height = 1;
    }

    // 带参
    public Box(int w, int h) {
        this.width = w;
        this.height = h;
    }

    // 调另一个构造
    public Box(int size) {
        this(size, size);
    }
}

this(...) 调本类其他构造——必须是构造体第一行

默认构造

如果不写任何构造,Java 自动给一个无参 public ClassName() {}

写了任何构造(带参的)→ 默认构造消失。要无参构造必须显式写

字段初始化

public class Config {
    // 初始化字段时给默认值
    private int retries = 3;
    private String host = "localhost";
    private List<String> tags = new ArrayList<>();

    // 实例初始化块(不常用)
    {
        host = System.getenv("HOST");
    }

    public Config() {
        // 构造里的赋值在字段初始化和实例块之后
    }
}

字段没显式初始化时的默认值:

  • 数值:0
  • boolean:false
  • 引用:null

final 字段

public class Order {
    private final long createdAt;        // 只能赋一次

    public Order() {
        createdAt = System.currentTimeMillis();   // ✅
    }

    public Order(long t) {
        createdAt = t;                            // ✅
    }
    // createdAt = 0;                              // ❌
}

final 字段:只能在构造里赋一次。其他地方不行。

static 字段

public class Counter {
    private static int total = 0;        // 类级别,所有实例共享

    public Counter() {
        total++;
    }

    public static int getTotal() {
        return total;
    }
}

new Counter(); new Counter(); new Counter();
Counter.getTotal();         // 3

static 成员属于,不属于实例。所有实例共享一份。

常量(static final)

public class Math2 {
    public static final double PI = 3.14159265358979;
    public static final int MAX_ITERATIONS = 100;
}

// 用
Math2.PI

约定:static final 字段全大写 + 下划线分隔。

static 初始化块

public class Config {
    private static final Map<String, Integer> CONSTANTS;

    static {
        CONSTANTS = new HashMap<>();
        CONSTANTS.put("a", 1);
        CONSTANTS.put("b", 2);
    }
}

类第一次加载时执行一次。线程安全。

但 Java 16+ 用 Map.of(...) 更简洁:

private static final Map<String, Integer> CONSTANTS = Map.of("a", 1, "b", 2);

getter / setter 模板

public class Person {
    private String name;

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

Java 没有 C# 的 property 语法——必须写完整方法。IDE(IntelliJ)一键生成。

或用 Lombok

import lombok.Data;

@Data    // 自动生成 getter / setter / toString / equals / hashCode
public class Person {
    private String name;
    private int age;
}

Lombok 是注解处理器——编译时生成代码。Java 项目里很常见。

或用 record第 12 篇)——更现代的"数据类"。

内部类

public class Outer {
    private int n = 1;

    // 内部类(inner class):每个实例隐式持有外部实例
    public class Inner {
        public void show() {
            System.out.println(n);    // 能访问外部字段
        }
    }

    // 静态嵌套类(static nested class):没有外部引用,像独立类
    public static class Nested {
        public void show() {
            System.out.println("nested");
        }
    }
}

// 用
var outer = new Outer();
var inner = outer.new Inner();           // 内部类需要 outer 实例
var nested = new Outer.Nested();          // 静态嵌套不需要

优先用 static nested class——内部类的"隐式外部引用"是常见内存泄漏源。

匿名内部类

Runnable r = new Runnable() {
    @Override
    public void run() {
        System.out.println("running");
    }
};

Java 8 起绝大多数场景用 lambda 替代:

Runnable r = () -> System.out.println("running");

toString / equals / hashCode

public class Person {
    private final String name;
    private final int age;

    public Person(String name, int age) { this.name = name; this.age = age; }

    @Override
    public String toString() {
        return "Person{name=" + name + ", age=" + age + "}";
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person p)) return false;
        return age == p.age && Objects.equals(name, p.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

HashMap / HashSet 必须正确实现 equals + hashCode——否则 contains / get 失效。规则:相等的对象 hashCode 必须相等。

用 record 自动免去这些样板:

public record Person(String name, int age) {}    // 自动有 equals/hashCode/toString

→ 下一篇 继承 + 多态