ソースを参照

docs: 更新20260723课堂笔记,同步代码变更——新增final关键字(final类/方法/变量/引用类型)和Shape抽象类练习代码

WanJL 1 日 前
コミット
1892744c70

+ 1 - 1
README.md

@@ -30,7 +30,7 @@
 | 2026-07-20 | [面向对象基础:类与对象、成员变量与成员方法、创建对象与使用成员](./课堂笔记/01-JavaSE基础-笔记/20260720-笔记.md) |
 | 2026-07-21 | [构造方法(构造器):构造方法引出、格式与特点、默认构造方法、无参构造方法、构造方法重载、有参构造方法调用、this 在构造方法中的应用、private 构造方法阻止外部创建对象、完整 Person 示例(4种构造方法重载)、课后作业回顾(Fisher-Yates 洗牌算法/Emp 员工封装/MathTools 回文数/Student 封装展示)](./课堂笔记/01-JavaSE基础-笔记/20260721-笔记.md) |
 | 2026-07-22 | [继承:继承的概念、格式、好处与弊端、is...a 使用场景、方法重写(@Override)、super 关键字调用父类成员、同名属性处理(this vs super)、变量的就近原则查找、this vs super 完整对比、继承中构造方法特点(子类默认调用 super()、父类无无参构造时的处理)、单继承与多层继承、Object 根类、访问修饰符在继承中的体现、随堂练习(学生成绩管理系统-构造方法版)、课后作业(猜数游戏面向对象版/BookManager图书管理系统)](./课堂笔记/01-JavaSE基础-笔记/20260722-笔记.md) |
-| 2026-07-23 | [抽象类:抽象类引出与概念、抽象类定义(abstract 关键字)、抽象类特点(不能实例化/可有构造方法/子类必须重写所有抽象方法或自身也是抽象)、抽象类代码示例(Animal→Cat/Dog 动物体系、Emp→javaEmp 员工体系、BaseService→UserService 服务层体系)](./课堂笔记/01-JavaSE基础-笔记/20260723-笔记.md) |
+| 2026-07-23 | [抽象类(abstract)+ final 关键字:抽象类引出与概念、抽象类定义(abstract 关键字)、抽象类特点(不能实例化/可有构造方法/子类必须重写所有抽象方法或自身抽象)、抽象类代码示例(Animal→Cat/Dog 动物体系、Emp→javaEmp 员工体系、BaseService→UserService 服务层体系);final 修饰类(禁止继承)、final 修饰方法(禁止重写)、final 修饰变量(变成常量)、final 引用类型(引用地址不可变但对象内容可修改)、final vs abstract 对比;随堂练习(Shape 抽象类计算周长+面积)](./课堂笔记/01-JavaSE基础-笔记/20260723-笔记.md) |
 
 ## 二、授课代码
 

+ 33 - 0
授课代码/c260723/src/course/Demo02.java

@@ -0,0 +1,33 @@
+package course;
+
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title Demo02
+ * @description final
+ * @create 2026/7/23
+ */
+public class Demo02 {
+    /*
+        如果一个类 不想让子类继承自己,那么可以在类上面使用final进行修饰
+
+        public final class 类名{
+
+        }
+        使用final修饰的类,不能被继承.
+        使用final修饰的变量,不能被修改,这个变量就变成了常量。只能调用,不能修改。
+        使用final修饰的方法,不能被子类重写。
+
+        修饰类的场景:
+            比如某个工具类,只能被调用,不能被继承。或者是一些特殊功能的类,比如字符串类
+            String 就是一个类,这个类就是使用final修饰的,就不能继承字符串类。
+
+        final 不能和 abstract 一起使用的,相互冲突
+     */
+    //使用final修饰的变量,不能被修改,这个变量就变成了常量。只能调用,不能修改。
+    final int i=10;
+    final Person p=new Person("1001","张三");
+
+
+}

+ 17 - 0
授课代码/c260723/src/course/FinalClass.java

@@ -0,0 +1,17 @@
+package course;
+
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title FinalClass
+ * @description
+ * @create 2026/7/23
+ */
+public class FinalClass {
+    final String SPRING="春天";
+
+    public final void showInfo(){
+        System.out.printf(SPRING);
+    }
+}

+ 45 - 0
授课代码/c260723/src/course/Person.java

@@ -0,0 +1,45 @@
+package course;
+
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title Person
+ * @description
+ * @create 2026/7/23
+ */
+public class Person {
+    private String id;
+    private String name;
+
+    public Person() {
+    }
+
+    public Person(String id, String name) {
+        this.id = id;
+        this.name = name;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String showInfo() {
+        return "Person{" +
+                "id='" + id + '\'' +
+                ", name='" + name + '\'' +
+                '}';
+    }
+}

+ 15 - 0
授课代码/c260723/src/course/SubClass.java

@@ -0,0 +1,15 @@
+package course;
+
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title SubClass
+ * @description
+ * @create 2026/7/23
+ */
+public class SubClass extends FinalClass{
+//    public final void showInfo(){
+//        System.out.printf(SPRING);
+//    }
+}

+ 20 - 0
授课代码/c260723/src/course/Test02.java

@@ -0,0 +1,20 @@
+package course;
+
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title Test02
+ * @description
+ * @create 2026/7/23
+ */
+public class Test02 {
+    public static void main(String[] args) {
+        Demo02 d=new Demo02();
+        //d.i=20; //final修饰的变量不能修改
+        d.p.setName("李四");
+        d.p.setId("1002");
+        String s = d.p.showInfo();
+        System.out.printf(s);
+    }
+}

+ 39 - 0
授课代码/c260723/src/exercise/exercise02/Circle.java

@@ -0,0 +1,39 @@
+package exercise.exercise02;
+
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title Circle
+ * @description 圆形类
+ * @create 2026/7/23
+ */
+public class Circle extends Shape{
+    private double radius;
+    private double pi=3.1415926;
+
+    public Circle(String color, double radius) {
+        super(color);   //调用父类的构造方法
+        this.radius = radius;   //为自己的私有变量传值
+    }
+
+    /**
+     * 计算面积
+     *
+     * @return
+     */
+    @Override
+    public double getArea() {
+        return pi*radius*radius;
+    }
+
+    /**
+     * 计算周长
+     *
+     * @return
+     */
+    @Override
+    public double getPerimeter() {
+        return 2*pi*radius;
+    }
+}

+ 39 - 0
授课代码/c260723/src/exercise/exercise02/Shape.java

@@ -0,0 +1,39 @@
+package exercise.exercise02;
+
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title Shape
+ * @description 图形抽象类
+ * @create 2026/7/23
+ */
+public abstract class Shape {
+    private String color;
+
+    public Shape(String color) {
+        this.color = color;
+    }
+
+    /**
+     * 计算面积
+     * @return
+     */
+    public abstract double getArea();
+
+    /**
+     * 计算周长
+     * @return
+     */
+    public abstract double getPerimeter();
+    /**
+     * 输出的方法
+     */
+    public void showInfo(){
+        System.out.print("颜色:"+this.color);
+        System.out.printf(",面积:%.2f",getArea());
+        System.out.printf(",周长:%.2f",getPerimeter());
+        System.out.println();
+    }
+
+}

+ 16 - 0
授课代码/c260723/src/exercise/exercise02/Test.java

@@ -0,0 +1,16 @@
+package exercise.exercise02;
+
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title Test
+ * @description
+ * @create 2026/7/23
+ */
+public class Test {
+    public static void main(String[] args) {
+        Circle circle = new Circle("红色",5);
+        circle.showInfo();
+    }
+}

+ 55 - 0
授课代码/c260723/src/exercise/exercise02/题目.md

@@ -0,0 +1,55 @@
+## 练习 2:形状抽象类——Shape 图形体系 ⭐(必做)
+
+**难度**:⭐⭐  
+**知识点**:抽象类定义、抽象方法(计算周长 + 计算面积)、子类重写所有抽象方法
+
+创建一个图形抽象体系,要求抽象父类中定义 **计算周长** 和 **计算面积** 的抽象方法。
+
+**`Shape` 抽象类**(父类):
+
+- **私有属性**:`color`(颜色,String)
+- **有参构造方法**:`Shape(String color)`
+- **抽象方法**:`double getArea()` —— 计算面积
+- **抽象方法**:`double getPerimeter()` —— 计算周长
+- **普通方法**:`showInfo()` —— 输出 `"颜色:xxx,面积:xxx,周长:xxx"`(通过调用 `getArea()` 和 `getPerimeter()` 获得)
+
+**`Circle` 类**(继承 Shape):
+
+- **新增私有属性**:`radius`(半径,double)
+- **构造方法**:`Circle(String color, double radius)`
+- **重写** `getArea()` —— 返回 `π × r²`(π 取 `3.1415926`)
+- **重写** `getPerimeter()` —— 返回 `2 × π × r`
+
+**`Rectangle` 类**(继承 Shape):
+
+- **新增私有属性**:`width`(宽度,double)、`height`(高度,double)
+- **构造方法**:`Rectangle(String color, double width, double height)`
+- **重写** `getArea()` —— 返回 `width × height`
+- **重写** `getPerimeter()` —— 返回 `2 × (width + height)`
+
+**`Triangle` 类**(继承 Shape):
+
+- **新增私有属性**:`a`(边长 a,double)、`b`(边长 b,double)、`c`(边长 c,double)
+- **构造方法**:`Triangle(String color, double a, double b, double c)`
+- **重写** `getArea()` —— 使用海伦公式:`s = (a+b+c)/2`,面积 = `√(s(s-a)(s-b)(s-c))`(`Math.sqrt()` 求平方根)
+- **重写** `getPerimeter()` —— 返回 `a + b + c`
+
+**测试类要求**:
+
+1. 创建 `Circle` 对象("红色", 5.0),调用 `showInfo()` 输出信息
+2. 创建 `Rectangle` 对象("蓝色", 4.0, 6.0),调用 `showInfo()` 输出信息
+3. 创建 `Triangle` 对象("绿色", 3.0, 4.0, 5.0),调用 `showInfo()` 输出信息
+
+**预期输出**(保留两位小数):
+
+```
+颜色:红色,面积:78.54,周长:31.42
+颜色:蓝色,面积:24.00,周长:20.00
+颜色:绿色,面积:6.00,周长:12.00
+```
+
+> **提示**:
+>
+> - 子类构造方法中必须调用 `super(color)` 初始化父类的 color 属性
+> - `Triangle` 的面积使用海伦公式:`double s = (a + b + c) / 2; double area = Math.sqrt(s * (s - a) * (s - b) * (s - c));`
+> - 输出时使用 `System.out.printf("%.2f", value)` 保留两位小数

+ 187 - 3
课堂笔记/01-JavaSE基础-笔记/20260723-笔记.md

@@ -267,7 +267,185 @@ public class UserService extends BaseService {
 
 ---
 
-## 三、随堂练习要点
+## 三、final 关键字
+
+### 1. final 的引出
+
+**文件**:`Demo02.java`
+
+在实际开发中,有些类、方法或变量不希望被改变:
+- 某个工具类,只能被调用,不希望被继承
+- 某些核心方法,不希望被子类重写(篡改)
+- 某些固定值,希望成为常量,不允许修改
+
+`final` 关键字就是用来解决这些问题的——**用于限制类、方法或变量被修改**。
+
+### 2. final 修饰类——禁止继承
+
+**文件**:`Demo02.java`、`FinalClass.java`
+
+```java
+// 使用 final 修饰的类,不能被继承
+public final class 类名 {
+    // ...
+}
+```
+
+**应用场景**:
+- 工具类(如 `Math`、`Arrays`),只能被调用,不能被继承
+- 特殊功能的类,如 `String` 类就是用 `final` 修饰的,不能被继承
+
+### 3. final 修饰方法——禁止重写
+
+**文件**:`FinalClass.java`、`SubClass.java`
+
+```java
+// 父类中的 final 方法
+public class FinalClass {
+    final String SPRING = "春天";
+
+    public final void showInfo() {
+        System.out.printf(SPRING);
+    }
+}
+
+// 子类无法重写父类的 final 方法
+public class SubClass extends FinalClass {
+    // ❌ 编译报错:不能重写父类的 final 方法
+    // public final void showInfo() {
+    //     System.out.printf(SPRING);
+    // }
+}
+```
+
+- `FinalClass` 类本身没有用 `final` 修饰,所以 `SubClass` 可以继承它
+- 但 `FinalClass` 中的 `showInfo()` 方法用 `final` 修饰,子类 **不能重写** 该方法
+- 注掉了 `SubClass` 中的重写代码,否则编译报错
+
+### 4. final 修饰变量——变成常量
+
+**文件**:`Demo02.java`、`Test02.java`
+
+```java
+// final 修饰基本类型变量——值不可修改
+final int i = 10;
+// i = 20;  // ❌ 编译报错:不能修改 final 变量的值
+
+// final 修饰引用类型变量——引用地址不可变,但对象内容可以修改
+final Person p = new Person("1001", "张三");
+// p = new Person("1002", "李四");  // ❌ 编译报错:不能修改引用地址
+p.setName("李四");  // ✅ 可以修改对象的属性
+p.setId("1002");
+System.out.printf(p.showInfo());  // 输出:Person{id='1002', name='李四'}
+```
+
+**关键区别**:
+
+| 变量类型 | final 的作用 | 示例 |
+|---------|-------------|------|
+| **基本类型**(int、double 等) | 数值本身不可修改 | `final int i = 10;` → `i=20;` 报错 |
+| **引用类型**(对象、数组等) | 引用地址不可修改,但对象 **属性** 可修改 | `final Person p = new Person(...)` → `p.setName(...)` 可以 |
+
+> **注意**:`final` 修饰引用类型变量时,只是保证这个变量不再指向其他对象,但该对象内部的 **成员变量** 仍然可以通过 setter 修改。
+
+### 5. final 与 abstract 的对比
+
+| 关键字 | 修饰类 | 修饰方法 | 修饰变量 |
+|--------|-------|---------|---------|
+| **`abstract`** | 类必须被继承 | 方法必须在子类中实现(无方法体) | 不能修饰变量 |
+| **`final`** | 类不能被继承 | 方法不能被重写 | 变量变成常量 |
+
+> ⚠️ **`final` 和 `abstract` 不能同时使用**,二者语义完全冲突:
+> - `abstract` 表示「需要被继承/重写」
+> - `final` 表示「不能被继承/重写」
+
+---
+
+## 四、随堂练习代码示例——Shape 抽象类(计算周长 + 计算面积)
+
+> 代码位于 `exercise/exercise02` 包中,对应课堂练习题第 2 题。
+
+### 抽象父类 Shape
+
+**文件**:`exercise/exercise02/Shape.java`
+
+```java
+package exercise.exercise02;
+
+public abstract class Shape {
+    private String color;
+
+    public Shape(String color) {
+        this.color = color;
+    }
+
+    /** 计算面积——抽象方法 */
+    public abstract double getArea();
+
+    /** 计算周长——抽象方法 */
+    public abstract double getPerimeter();
+
+    /** 输出信息——普通方法(调用抽象方法) */
+    public void showInfo() {
+        System.out.print("颜色:" + this.color);
+        System.out.printf(",面积:%.2f", getArea());
+        System.out.printf(",周长:%.2f", getPerimeter());
+        System.out.println();
+    }
+}
+```
+
+- 定义了两个抽象方法:`getArea()` 和 `getPerimeter()`
+- 定义了一个普通方法 `showInfo()`,内部调用抽象方法输出结果
+- 体现了 **模板方法** 的思想——父类定义输出框架,子类提供具体的面积和周长计算
+
+### 子类 Circle
+
+**文件**:`exercise/exercise02/Circle.java`
+
+```java
+package exercise.exercise02;
+
+public class Circle extends Shape {
+    private double radius;
+    private double pi = 3.1415926;
+
+    public Circle(String color, double radius) {
+        super(color);           // 调用父类构造方法
+        this.radius = radius;   // 初始化子类属性
+    }
+
+    @Override
+    public double getArea() {
+        return pi * radius * radius;
+    }
+
+    @Override
+    public double getPerimeter() {
+        return 2 * pi * radius;
+    }
+}
+```
+
+### 测试类 Test
+
+**文件**:`exercise/exercise02/Test.java`
+
+```java
+package exercise.exercise02;
+
+public class Test {
+    public static void main(String[] args) {
+        Circle circle = new Circle("红色", 5);
+        circle.showInfo();
+        // 输出:颜色:红色,面积:78.54,周长:31.42
+    }
+}
+```
+
+---
+
+## 五、随堂练习要点
 
 **练习目标**:理解抽象类的定义和使用
 
@@ -277,7 +455,7 @@ public class UserService extends BaseService {
 
 ---
 
-## 、面试常见问题
+## 、面试常见问题
 
 **Q1:抽象类能不能被实例化?**
 > 不能。抽象类不能直接 `new` 创建对象。
@@ -294,9 +472,15 @@ public class UserService extends BaseService {
 **Q5:`abstract` 和 `final` 能否同时修饰一个类或方法?**
 > 不能。`abstract` 表示需要被继承/重写,`final` 表示不能被继承/重写,二者语义冲突。
 
+**Q6:`final` 修饰引用类型变量时,对象内容还能修改吗?**
+> 可以。`final` 修饰引用类型变量时,只是保证引用地址不变(不能重新指向其他对象),但该对象内部的成员变量仍然可以通过 setter 修改。
+
+**Q7:`final` 修饰的类有哪些常见例子?**
+> `String` 类、`Math` 类、`Integer` 等包装类都是用 `final` 修饰的,它们不能被继承。
+
 ---
 
-## 五、拓展阅读
+## 、拓展阅读
 
 - [Java 抽象类(Oracle 官方文档)](https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html)
 - 抽象类 vs 接口(Interface)的区别(将在后续课程中讲解)