Java SE 基础学习笔记(一):面向对象、继承多态、抽象接口与异常(JDK 8)

Java SE 基础学习笔记(一):面向对象、继承多态、抽象接口与异常(JDK 8)

适用版本:JDK 8

学习目标:把"类、对象、封装、继承、多态、抽象、接口、内部类、异常"串成一个完整的知识框架。

阅读建议:代码按知识点拆分;为展示继承、接口等关系,部分片段会把相关类型放在一起。实际运行时,请将每个 public class 放在同名的 .java 文件中,并补齐片段依赖的类型。


一、学习路线与核心问题

这一节的核心不是背概念,而是回答四个问题:

  1. 如何用类和对象描述现实或业务中的事物?
  2. 如何隐藏实现细节,并让代码容易修改和扩展?
  3. 为什么"父类引用指向子类对象"能调用子类重写的方法?
  4. 程序出现异常时,应该在哪里发现、在哪里处理、如何避免资源泄漏?
text 复制代码
类(抽象的设计图) ── new ──> 对象(具体实例)
        │                         │
        ├─ 封装:保护数据           ├─ 状态:字段 / 属性
        ├─ 继承:复用共性           └─ 行为:方法
        └─ 多态:统一调用、按实际对象执行

异常机制:发现异常 → 抛出 / 传播 → 捕获处理 → 资源收尾

二、面向对象编程(OOP)

2.1 什么是面向对象

面向对象编程(Object-Oriented Programming,OOP)是一种组织程序的思路:用 描述一类事物的共同特征,再用对象表示一个个具体实例。对象把自己的数据和可执行的行为组织在一起。

以学生为例:

概念 示例
类(Class) Student,描述"学生"这一类事物
属性 / 字段(Field) nameage
方法(Method) study()introduce()
对象(Object) new Student("Mingyu", 20)

"字段 + 方法 = 类"可以帮助初学理解,但并不严谨。一个类还可以包含构造器、初始化块、内部类等;而某些类可能只有字段或只有工具方法。

2.2 面向过程与面向对象

思路 关注点 适合的表达方式
面向过程 先做什么、后做什么 把任务拆成步骤和函数
面向对象 谁拥有数据、谁负责行为 把状态和行为交给相应对象

例如"完成一次付款":

text 复制代码
面向过程:校验金额 → 选择渠道 → 扣款 → 记录订单 → 通知用户

面向对象:Order 负责订单状态;
          Payment 负责付款能力;
          AlipayPayment / WeChatPayment 负责各自渠道的具体实现。

两种思路并不对立。Java 的方法内部仍然常常以步骤执行;面向对象主要帮助我们在程序规模变大时划分职责。

2.3 面向对象的核心思想

初学阶段常把封装、继承、多态 称为 Java 面向对象的三大特性。除此之外,抽象也是非常重要的思想:从众多具体事物中提炼共同特征和规则。


三、类、对象与引用

3.1 创建对象

java 复制代码
public class Student {
    String name;
    int age;

    public void study() {
        System.out.println(name + " 正在学习 Java");
    }
}

创建对象时:

java 复制代码
Student student = new Student();
student.name = "Mingyu";
student.age = 20;
student.study();

这行代码可以拆开理解:

text 复制代码
Student             :引用变量的声明类型
student             :引用变量名
new Student()       :创建一个 Student 对象
=                   :把对象的引用赋给变量

student 保存的是对象的引用,不是把整个对象复制进变量中。

3.2 类与对象的关系

text 复制代码
Student 类(模板)
  ├─ name
  ├─ age
  └─ study()

new Student() ──> 一个具体 Student 对象
student ─────────> 指向该对象的引用

3.3 命名规范

这不是语法强制,但建议从一开始遵守:

项目 建议 示例
类、接口、枚举 大驼峰(UpperCamelCase) StudentTestException
方法、变量 小驼峰(lowerCamelCase) calculateTotal()userName
常量 全大写,下划线分隔 MAX_AGE
包名 全小写,通常使用域名倒写 com.example.demo

四、静态成员与实例成员

4.1 静态字段和静态方法

static 修饰的成员属于类本身,由该类的所有对象共享。推荐使用"类名.成员名"访问。

java 复制代码
public class Counter {
    static int total = 0;

    public Counter() {
        total++;
    }

    public static void printTotal() {
        System.out.println("对象总数:" + total);
    }
}
java 复制代码
new Counter();
new Counter();
Counter.printTotal(); // 对象总数:2

4.2 实例字段和实例方法

没有 static 的成员属于对象,每个对象都有自己的实例状态。

java 复制代码
public class Person {
    String name;

    public void sayHello() {
        System.out.println("你好,我是 " + name);
    }
}
java 复制代码
Person p1 = new Person();
p1.name = "Alice";

Person p2 = new Person();
p2.name = "Bob";

p1.sayHello(); // 你好,我是 Alice
p2.sayHello(); // 你好,我是 Bob

4.3 静态方法为什么不能直接调用实例方法

静态方法可以在没有创建任何对象时被调用,因此它没有隐式的 this 对象;而实例字段、实例方法必须依附于某个具体对象。

java 复制代码
public class Demo {
    int age = 18;

    public void instanceMethod() {
        System.out.println(age);
    }

    public static void staticMethod() {
        // System.out.println(age);    // 编译错误:没有具体对象
        // instanceMethod();           // 编译错误:没有具体对象

        Demo demo = new Demo();
        System.out.println(demo.age);
        demo.instanceMethod();
    }
}

反过来,实例方法可以直接访问同类的静态成员:

java 复制代码
public void instanceMethod() {
    System.out.println(Counter.total);
    Counter.printTotal();
}

4.4 main 为什么是静态方法

JVM 启动程序时,需要先找到入口:

java 复制代码
public static void main(String[] args)

此时 JVM 还没有帮我们创建任何对象,所以入口方法必须是静态方法。一个项目中可以存在多个带 main 的练习类或启动类;每次运行配置只会选择其中一个作为当前入口。


五、形参与实参:Java 只有值传递

5.1 基本数据类型

java 复制代码
public class PassByValueDemo {
    public static void main(String[] args) {
        int number = 10;
        change(number);
        System.out.println(number); // 10
    }

    static void change(int value) {
        value = 99;
    }
}

调用 change(number) 时,number 的值 10 被复制给了形参 value。修改 value 不会影响原变量。

5.2 对象引用

java 复制代码
public class PassByValueObjectDemo {
    public static void main(String[] args) {
        Student student = new Student();
        student.name = "Mingyu";

        rename(student);
        System.out.println(student.name); // Ray
    }

    static void rename(Student value) {
        value.name = "Ray";
    }
}

这里看起来像"引用传递",但更准确的说法是:

**Java 始终只有值传递。**传入的是对象引用的副本;两个引用都指向同一个对象,因此可以通过该副本修改对象的状态。

如果在方法里让形参指向一个新对象,调用方的引用不会改变:

java 复制代码
static void replace(Student value) {
    value = new Student();
    value.name = "New Name";
}

六、构造器与 this

6.1 构造器的作用

构造器用于初始化新对象。它的规则:

  1. 名称必须与类名相同;
  2. 没有返回类型,连 void 也不能写;
  3. 创建对象时由 new 自动调用;
  4. 只有当类中完全没有声明任何构造器时,编译器才会自动提供无参构造器。
java 复制代码
public class User {
    private String name;
    private int age;

    public User() {
        this("未命名用户", 0);
    }

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

6.2 this 的含义

this 是"当前对象"的引用,常用于区分成员变量和形参:

java 复制代码
public User(String name, int age) {
    this.name = name;
    this.age = age;
}

左边的 this.name 是对象字段,右边的 name 是传入的形参。this 不能出现在静态方法中,因为静态方法没有当前对象。


七、对象在内存中的概念模型

下面是帮助理解的简化模型;JVM 的具体实现会随版本和虚拟机不同而变化。

text 复制代码
方法调用栈(栈帧)                 堆(Heap)
┌────────────────┐             ┌──────────────────────┐
│ student 引用 ────────────────> │ Student 对象         │
│                                │ name = "Mingyu"      │
│                                │ age = 20             │
└────────────────┘             └──────────────────────┘

类的元数据、方法信息等由 JVM 管理(Java 8 中常称 Metaspace / 元空间)。

记住三个结论即可:

  1. 局部变量和方法调用相关的数据可以理解为与栈帧相关;
  2. new 创建的普通对象通常位于堆中;
  3. 变量保存的是对象引用,多个引用可以指向同一个对象。

八、封装:保护数据,而不是机械地生成 Getter / Setter

8.1 为什么需要封装

如果字段全部公开,任何代码都可以写出不合理的数据:

java 复制代码
// 不推荐
public int age;

更好的做法是隐藏字段,并只暴露必要的操作:

java 复制代码
public class Account {
    private double balance;

    public double getBalance() {
        return balance;
    }

    public void deposit(double amount) {
        if (amount <= 0) {
            throw new IllegalArgumentException("存款金额必须大于 0");
        }
        balance += amount;
    }

    public boolean withdraw(double amount) {
        if (amount <= 0 || amount > balance) {
            return false;
        }
        balance -= amount;
        return true;
    }
}

这里外部代码不能任意修改 balance,只能通过 deposit()withdraw() 改变余额,从而保证规则得到执行。

8.2 高内聚、低耦合

text 复制代码
高内聚:一个类专注完成自己的职责。
低耦合:类之间只通过少量、清晰的接口合作,不依赖彼此内部细节。

封装并不等于"每个字段都必须生成 getter/setter"。如果某个属性不应被外部修改,就不应该提供 setter。


九、方法重载(Overload)

方法重载指在同一个类中,方法名相同、参数列表不同(参数数量、类型或顺序不同)。

java 复制代码
public class PrintUtil {
    public void print(int value) {
        System.out.println(value);
    }

    public void print(String value) {
        System.out.println(value);
    }

    public void print(String value, int times) {
        for (int i = 0; i < times; i++) {
            System.out.println(value);
        }
    }
}

以下情况不能构成重载:

java 复制代码
// 错误示例:仅返回类型不同,参数列表相同
// public int add(int a, int b) { return a + b; }
// public double add(int a, int b) { return a + b; }

println 就是常见的重载例子:它可以接收字符串、整数、布尔值、对象等不同类型的参数。


十、继承与访问修饰符

10.1 继承

当两个类是明确的 "is-a(是一个)" 关系时,可以使用继承复用共性。

java 复制代码
public class Animal {
    protected String name;

    public Animal(String name) {
        this.name = name;
    }

    public void eat() {
        System.out.println(name + " 正在进食");
    }
}

public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    public void bark() {
        System.out.println(name + ":汪汪");
    }
}
text 复制代码
Dog is an Animal(狗是一种动物)        → 适合继承
Dog has an Owner(狗拥有主人)          → 更适合组合,而非继承

Object 本身外,每个 Java 类都直接或间接继承 Object。Java 的类只支持单继承,但一个类可以实现多个接口。

10.2 访问修饰符

修饰符 同一个类 同一个包 不同包的子类 其他位置
private 可以 不可以 不可以 不可以
不写修饰符(default / package-private) 可以 可以 不可以 不可以
protected 可以 可以 可以,但跨包时通常只能通过继承关系访问 不可以
public 可以 可以 可以 可以

父类的 private 成员不能被子类直接访问,也不能被子类重写;需要时应通过父类提供的受保护或公开方法访问。

10.3 super 与构造器调用

super 用于访问可访问的父类成员,或调用父类构造器:

java 复制代码
public Dog(String name) {
    super(name); // 必须位于构造器的第一行
}

如果子类构造器没有显式写 super(...)this(...),编译器会尝试在第一行插入 super()。如果父类没有可访问的无参构造器,子类必须显式选择一个可访问的父类构造器。


十一、方法重写(Override)

子类可以为继承到的实例方法提供自己的实现,这叫方法重写。

java 复制代码
public class Animal {
    public void speak() {
        System.out.println("动物发出声音");
    }
}

public class Dog extends Animal {
    @Override
    public void speak() {
        System.out.println("汪汪");
    }
}

重写需要满足:

  1. 有继承关系;
  2. 方法名和参数列表相同;
  3. 返回类型相同,或是父类返回类型的子类型(协变返回);
  4. 子类方法的访问权限不能更严格;
  5. 不能抛出比父类方法更宽泛的受检异常
  6. 建议始终加上 @Override,让编译器帮助检查。

以下成员不参与普通的实例方法重写:

成员 说明
static 方法 属于类;子类同名方法属于隐藏(method hiding),不是重写
final 实例方法 不允许被重写
private 方法 子类不可见,不能重写
构造器 不会被继承,因此不存在重写

十二、多态:父类引用,子类对象

12.1 最核心的写法

java 复制代码
Animal animal = new Dog();
animal.speak(); // 汪汪

这行代码中:

text 复制代码
Animal animal  :引用变量的声明类型(编译期类型)
new Dog()      :对象的实际类型(运行期类型)

调用被子类重写的实例方法 时,JVM 会根据对象的实际类型进行动态绑定,因此执行 Dog.speak()

12.2 编译期与运行期分别决定什么

这是多态中最容易混淆的一点:

text 复制代码
编译期:看引用变量的声明类型,决定"能否调用这个成员"。
运行期:对被重写的实例方法,看对象实际类型,决定"执行哪一版实现"。
java 复制代码
Animal animal = new Dog();
animal.speak(); // 可以调用:Animal 中声明了 speak()

// animal.bark(); // 编译错误:Animal 类型中没有 bark()

12.3 多态的价值

java 复制代码
public static void makeAnimalSpeak(Animal animal) {
    animal.speak();
}

makeAnimalSpeak(new Dog()); // 汪汪
makeAnimalSpeak(new Cat()); // 喵喵

调用方只依赖 Animal 的共同能力,不必为每一种动物写一套调用逻辑。之后加入 Bird,通常不需要修改 makeAnimalSpeak()

常见业务场景包括付款方式、消息通知、员工薪资计算、文件导出等。

12.4 多态的边界

  1. 多态主要体现为实例方法的重写,字段没有运行时多态;
  2. 静态方法按引用的声明类型绑定,不是动态分派;
  3. 父类引用不能直接访问子类特有方法;
  4. 向上转型自动且安全;向下转型需要显式强转并检查实际类型。
java 复制代码
Animal animal = new Dog(); // 向上转型,安全

if (animal instanceof Dog) {
    Dog dog = (Dog) animal; // 向下转型
    dog.bark();
}

数值强转可能发生精度损失;引用强转不存在"丢失精度"。向上转型只是让子类特有成员暂时不能通过父类引用直接访问。


十三、static、代码块与 final

13.1 初始化顺序

java 复制代码
public class InitDemo {
    static {
        System.out.println("静态代码块:类首次初始化时执行一次");
    }

    {
        System.out.println("实例初始化块:每次创建对象时执行");
    }

    public InitDemo() {
        System.out.println("构造器:每次创建对象时执行");
    }
}

首次 new InitDemo() 时,简化理解为:

text 复制代码
静态字段 / 静态代码块(按源码顺序,且只执行一次)
→ 实例字段 / 实例初始化块(每次对象创建)
→ 构造器体(每次对象创建)

13.2 静态导入

import static 导入的是某个类的静态成员,不是"导入包"。

java 复制代码
import static java.lang.Math.PI;
import static java.lang.Math.max;

double radius = 2;
double perimeter = 2 * PI * radius;
int bigger = max(3, 5);

静态导入过多会降低代码可读性,通常只在常用常量、测试断言等场景谨慎使用。

13.3 final

用法 含义
final 变量 变量只能赋值一次;若是对象引用,不能重新指向其他对象,但对象内部状态仍可能变化
final 方法 不能被子类重写
final 不能被继承

十四、抽象类

14.1 为什么需要抽象类

当父类只提供共同状态和部分共同实现,但某个行为必须由具体子类决定时,可以使用抽象类。

java 复制代码
public abstract class Shape {
    private String color;

    public Shape(String color) {
        this.color = color;
    }

    public String getColor() {
        return color;
    }

    public abstract double area();
}

public class Circle extends Shape {
    private double radius;

    public Circle(String color, double radius) {
        super(color);
        this.radius = radius;
    }

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

结论:

  1. 抽象类不能直接 new
  2. 抽象类可以有字段、构造器、普通方法、静态方法和抽象方法;
  3. 抽象方法没有方法体;
  4. 具体子类必须实现所有继承到的抽象方法,否则子类也必须声明为 abstract
  5. 抽象类的构造器可以存在;创建具体子类对象时,父类构造器仍会执行。

十五、接口:定义能力与约定

接口更强调"能做什么",常用于定义多个类共同遵守的能力或规范。

java 复制代码
public interface Flyable {
    void fly();
}

public interface Swimmable {
    void swim();
}

public class Duck implements Flyable, Swimmable {
    @Override
    public void fly() {
        System.out.println("鸭子飞行");
    }

    @Override
    public void swim() {
        System.out.println("鸭子游泳");
    }
}

在 JDK 8 中,接口可以包含:

成员 说明
常量 默认是 public static final
抽象方法 默认是 public abstract
默认方法 使用 default,可以有方法体
静态方法 使用 static,可以有方法体

接口不能被实例化,也不能声明构造器。类可以实现多个接口;接口本身也可以继承多个接口:

java 复制代码
public interface Amphibious extends Flyable, Swimmable {
}

15.1 面向接口编程

java 复制代码
public interface Payment {
    void pay(double amount);
}

public class AlipayPayment implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("支付宝付款:" + amount);
    }
}

public class PaymentService {
    public void checkout(Payment payment, double amount) {
        payment.pay(amount);
    }
}

PaymentService 依赖的是 Payment 这个约定,而不是某个具体渠道。以后替换为微信支付、银行卡支付时,调用方通常不需要改变。

15.2 抽象类与接口如何选择

场景 更适合
多个类有共同字段、构造逻辑、部分通用实现 抽象类
只需要描述共同能力或规范,且可能由不相关的类实现 接口
需要让一个类具备多种能力 多个接口

十六、内部类

内部类是定义在另一个类内部的类。常见形式如下:

类型 特点
成员内部类 定义在外部类成员位置,通常依赖外部类对象
静态内部类 static 修饰,不依赖外部类对象
局部内部类 定义在方法、构造器或代码块内部
匿名内部类 没有类名,在创建对象时同时给出实现

匿名内部类示例:

java 复制代码
Runnable task = new Runnable() {
    @Override
    public void run() {
        System.out.println("执行任务");
    }
};

task.run();

注意:

java 复制代码
new TestException().a();

这只是"创建一个对象后立刻调用 a()",不是 匿名内部类。匿名内部类必须有紧跟在 new 类型() 后面的类体:

java 复制代码
new Runnable() {
    @Override
    public void run() {
    }
};

十七、异常机制

17.1 异常体系

text 复制代码
Throwable
├─ Error
│  ├─ OutOfMemoryError
│  └─ StackOverflowError
└─ Exception
   ├─ RuntimeException(非受检异常)
   │  ├─ NullPointerException
   │  ├─ ArithmeticException
   │  └─ ArrayIndexOutOfBoundsException
   └─ 其他 Exception(受检异常)
      └─ IOException
类型 说明 编译器是否强制处理
Error 通常表示严重问题,如内存不足、栈溢出;一般不建议业务代码试图恢复
运行时异常 常见于空指针、除零、下标越界、非法参数等
受检异常 常见于文件、网络、数据库等外部操作失败 是:必须捕获或声明 throws

不要简单地把 Error 理解成"JVM 抛出"、把 Exception 理解成"程序逻辑错误"。两者的真实边界更复杂;初学阶段重点是区分"是否可恢复、是否要求编译期处理"。

17.2 try-catch-finally

java 复制代码
public class DivideDemo {
    public static void main(String[] args) {
        try {
            int result = 10 / 0;
            System.out.println(result);
        } catch (ArithmeticException e) {
            System.out.println("除数不能为 0");
            e.printStackTrace();
        } finally {
            System.out.println("任务结束");
        }
    }
}

执行过程:

text 复制代码
进入 try
→ 发生 ArithmeticException
→ 跳过 try 中剩余语句
→ 进入匹配的 catch
→ 执行 finally(通常会执行)
→ 继续执行 finally 之后的代码

finally 常用于收尾,但不是绝对保证执行:例如调用 System.exit()、进程被强制终止或 JVM 崩溃时,它可能不会执行。

多个 catch 时,必须先写具体的子类异常,再写一般的父类异常:

java 复制代码
try (java.io.FileReader reader = new java.io.FileReader("note.txt")) {
    System.out.println(reader.read());
} catch (java.io.FileNotFoundException e) {
    // 更具体的异常
} catch (java.io.IOException e) {
    // 更一般的异常
}

17.3 throwthrows

关键字 位置 作用
throw 方法体、构造器或代码块内部 真正创建并抛出一个异常对象
throws 方法声明处 声明该方法可能向调用方传播的异常,主要用于受检异常
java 复制代码
public int divide(int a, int b) {
    if (b == 0) {
        throw new ArithmeticException("除数不能为 0");
    }
    return a / b;
}

ArithmeticException 是运行时异常,因此上述方法即使不写 throws ArithmeticException 也可以编译和传播异常。真正使异常离开 divide() 的是 throw new ...

受检异常的例子:

java 复制代码
import java.io.FileReader;
import java.io.IOException;

public class FileDemo {
    public static void readFile() throws IOException {
        FileReader reader = new FileReader("note.txt");
        reader.close();
    }
}

调用 readFile() 的代码必须捕获 IOException,或继续用 throws IOException 向上声明。

17.4 更推荐的资源处理方式:try-with-resources

文件流、网络连接、数据库连接等资源应及时关闭。JDK 7 及以后优先使用 try-with-resources:

java 复制代码
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class ReadFileDemo {
    public static void main(String[] args) {
        try (BufferedReader reader = new BufferedReader(new FileReader("note.txt"))) {
            System.out.println(reader.readLine());
        } catch (IOException e) {
            System.out.println("读取文件失败:" + e.getMessage());
        }
    }
}

资源会在 try 结束时自动关闭,通常比手写 finally 更安全、简洁。

17.5 自定义异常

当业务规则需要表达明确错误时,可以定义自定义异常:

java 复制代码
public class AgeOutOfRangeException extends Exception {
    public AgeOutOfRangeException(String message) {
        super(message);
    }
}
java 复制代码
public class AgeValidator {
    public static void validate(int age) throws AgeOutOfRangeException {
        if (age < 0 || age > 150) {
            throw new AgeOutOfRangeException("年龄必须在 0 到 150 之间");
        }
    }

    public static void main(String[] args) {
        try {
            validate(200);
        } catch (AgeOutOfRangeException e) {
            System.out.println(e.getMessage());
        }
    }
}

17.6 异常处理建议

  1. 能在入口校验的预期问题,优先用清晰的 if 判断;
  2. 当前方法不知道如何恢复时,再抛异常交给上层决定;
  3. 不要随意捕获 Throwable
  4. 不要吞掉异常:空的 catch 会让问题更难排查;
  5. printStackTrace() 适合学习和临时排查;生产代码应结合日志和业务提示;
  6. 异常信息要包含上下文,例如"订单号、文件路径、输入参数范围"等;
  7. 不要把异常当作普通流程控制工具。

十八、常见易错点速查

易错点 正确理解
Java 有"引用传递" Java 只有值传递;对象引用的副本被传入方法
静态方法绝不能调用普通方法 静态方法不能直接调用实例方法;可以先创建对象再调用
所有类只能有一个 main 一个项目可有多个入口类;一次运行选择一个入口
static 方法能被重写 静态方法是隐藏,不是实例方法重写
父类引用调用方法只看左边类型 编译期看左边决定可调用成员;运行期重写方法看实际对象
强制向下转型会"丢失方法" 向上转型会隐藏子类特有成员;向下转型恢复可见性,需先判断 instanceof
抽象类只有抽象方法 抽象类也可以有字段、构造器和普通方法
throws 就是在抛异常 throw 才真正抛出;throws 是声明或继续传播责任
finally 一定执行 通常执行,但 System.exit() 等情况是例外

十九、复习清单

学完后,应该能不看资料回答:

  • 类、对象、字段、方法、引用分别是什么?
  • 静态成员和实例成员的差别是什么?为什么 main 是静态的?
  • Java 参数传递为什么只有值传递?
  • 构造器、thissuper 分别解决什么问题?
  • 封装为什么不是"无脑生成 getter/setter"?
  • 方法重载和重写有什么区别?
  • 继承、多态、向上转型、向下转型之间有什么关系?
  • 抽象类与接口各适用于什么场景?
  • 受检异常、运行时异常、Error 的区别是什么?
  • throwthrowstry-catch-finally 如何配合?

二十、练习建议

  1. 创建 Student 类:私有化姓名和年龄,为年龄设置合法范围;
  2. 创建 AnimalDogCat,用父类引用数组依次调用 speak()
  3. 创建 Payment 接口,实现两个支付类,并让一个统一服务调用它们;
  4. 编写一个 divide(a, b) 方法:除数为 0 时给出清晰错误信息;
  5. 使用 try-with-resources 读取一个文本文件,并分别处理"文件不存在"和"读取失败"。

结语

这一节的主线可以概括为:

用类抽象事物,用对象保存状态;用封装保护规则,用继承复用共性,用多态降低耦合;在异常发生时,让合适的层级决定如何处理。

后续学习集合、IO、多线程、数据库和框架时,今天的类、接口、多态和异常都会反复出现。先把这些基础概念理解准确,比记住更多语法更重要。


相关推荐
天远数科2 小时前
风险治理实战:基于天远车信盟出险构建自动化理赔核保流水线
java·网络·人工智能·自动化
骇客野人2 小时前
SpringBoot电商系统用户注册、登录、留存及数据埋点设计与落地实施方案
java·spring boot·后端
qiuhaipeng12 小时前
Claude code 升级后上下文长度变短问题
java·前端·数据库
wxwx_bscxy3223 小时前
基于Python新冠疫情可视化分析系统的设计与实现
java·数据库·spring boot·python·微信小程序·sqlite
evans在进步4 小时前
Tomcat NIO 工作原理详解:从 Acceptor、Poller 到容器处理链
java·tomcat·nio
渡我白衣5 小时前
并查集:基础认识与模拟实现
android·java·javascript·数据结构·c++·算法·并查集
电商API_180079052475 小时前
电商商品价格监控工具淘宝京东商品价格抓取API项目实操分享
java·大数据·开发语言·前端·数据挖掘
zzzll11115 小时前
深度剖析:HashMap 并发死循环与 ConcurrentHashMap 两代演进全解
java·开发语言
秋名RG6 小时前
2026/5/27 生产事故复盘与整改方案
java