继承与多态动手动脑

  1. 实验代码
// 祖父类
class GrandParent {
    public GrandParent() {
        System.out.println("GrandParent 无参构造方法");
    }

    public GrandParent(String msg) {
        System.out.println("GrandParent 带参构造方法:" + msg);
    }
}

// 父类
class Parent extends GrandParent {
    public Parent() {
        // 显式调用GrandParent的带参构造方法,必须放在子类构造方法第一句
        super("调用GrandParent带参构造");
        System.out.println("Parent 无参构造方法");
    }
}

// 子类
class Child extends Parent {
    public Child() {
        // 隐式调用Parent的无参构造方法
        System.out.println("Child 无参构造方法");
    }
}

// 测试类
public class TestInherits {
    public static void main(String[] args) {
        new Child();
    }
}

3. 实验结果

GrandParent 带参构造方法:调用GrandParent带参构造
Parent 无参构造方法
Child 无参构造方法

4. 结论

  • 子类构造方法默认会隐式调用父类的无参构造方法。
  • 通过super关键字调用父类构造方法时,该语句必须是子类构造方法中的第一句,否则会编译错误。
  • 若父类没有无参构造方法,子类构造方法必须显式通过super调用父类的带参构造方法,否则编译失败。

(二)继承条件下访问权限验证

1. 实验目的

验证public、private、protected、default四种访问权限在继承中的作用范围。

2. 实验代码(分两个包)

包1:com.example.parent

package com.example.parent;

// 父类
public class Parent {
    public String publicField = "public字段";
    private String privateField = "private字段";
    protected String protectedField = "protected字段";
    String defaultField = "default字段"; // 默认权限

    public void publicMethod() {
        System.out.println("Parent public方法");
    }

    private void privateMethod() {
        System.out.println("Parent private方法");
    }

    protected void protectedMethod() {
        System.out.println("Parent protected方法");
    }

    void defaultMethod() {
        System.out.println("Parent default方法");
    }
}

包2:com.example.child(同包子类)

package com.example.parent;

// 同包子类
public class SamePackageChild extends Parent {
    public void accessParentField() {
        System.out.println(publicField); // 可访问
        // System.out.println(privateField); // 编译错误,private不可访问
        System.out.println(protectedField); // 可访问
        System.out.println(defaultField); // 可访问(同包)
    }

    public void callParentMethod() {
        publicMethod(); // 可访问
        // privateMethod(); // 编译错误,private不可访问
        protectedMethod(); // 可访问
        defaultMethod(); // 可访问(同包)
    }
}

包3:com.example.other(不同包子类)

package com.example.other;

import com.example.parent.Parent;

// 不同包子类
public class DifferentPackageChild extends Parent {
    public void accessParentField() {
        System.out.println(publicField); // 可访问
        // System.out.println(privateField); // 编译错误
        System.out.println(protectedField); // 可访问(不同包子类)
        // System.out.println(defaultField); // 编译错误,default不同包不可访问
    }

    public void callParentMethod() {
        publicMethod(); // 可访问
        // privateMethod(); // 编译错误
        protectedMethod(); // 可访问(不同包子类)
        // defaultMethod(); // 编译错误,default不同包不可访问
    }
}

3. 实验结论

访问权限 同一类 同一包非子类 同一包子类 不同包子类 不同包非子类
public
private
protected
default

(三)final类与不可变类验证

1. 实验目的

验证final修饰的类不可继承、final修饰的方法不可覆盖、final修饰的变量不可修改,以及不可变类的特性。

2. 实验代码

// final类,不可被继承
final class FinalClass {
    // final方法,不可被覆盖
    public final void finalMethod() {
        System.out.println("FinalClass final方法");
    }
}

// 尝试继承final类,编译错误
// class SubClass extends FinalClass {}

// 不可变类示例(类似String)
class ImmutableClass {
    private final String name; // final变量,初始化后不可修改
    private final int age;

    // 构造方法初始化所有final变量
    public ImmutableClass(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 只提供getter,不提供setter
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

// 测试类
public class TestFinal {
    public static void main(String[] args) {
        // 测试final变量
        final int num = 10;
        // num = 20; // 编译错误,final变量不可修改

        // 测试不可变类
        ImmutableClass ic = new ImmutableClass("张三", 20);
        System.out.println("姓名:" + ic.getName() + ",年龄:" + ic.getAge());
        // 无法修改ic的name和age,因为没有setter且变量为final
    }
}

3. 实验结论

  • final修饰的类不能被继承,否则编译错误。
  • final修饰的方法不能被子类覆盖,否则编译错误。
  • final修饰的变量(基本类型)初始化后不可修改;修饰引用类型时,引用地址不可变,但对象内部属性可修改(需通过类设计限制,如不可变类不提供setter)。
  • 不可变类(如String、上述ImmutableClass)的对象创建后,属性无法修改,可安全用于多线程环境,无需加锁。

(四)Object类toString()方法重写验证

1. 实验目的

验证默认toString()方法的输出,以及重写后自定义输出的效果。

2. 实验代码

// 未重写toString()的类
class NoOverrideToString {
    private String info = "未重写toString()";
}

// 重写toString()的类
class OverrideToString {
    private String name;
    private int id;

    public OverrideToString(String name, int id) {
        this.name = name;
        this.id = id;
    }

    // 重写toString()方法
    @Override
    public String toString() {
        return "OverrideToString{name='" + name + "', id=" + id + "}";
    }
}

// 测试类
public class TestToString {
    public static void main(String[] args) {
        // 未重写toString(),输出默认格式:类名@哈希码(十六进制)
        NoOverrideToString no = new NoOverrideToString();
        System.out.println(no); // 输出:com.example.NoOverrideToString@1c5f743

        // 重写toString(),输出自定义格式
        OverrideToString ot = new OverrideToString("李四", 1001);
        System.out.println(ot); // 输出:OverrideToString{name='李四', id=1001}

        // 验证“+”运算中隐式调用toString()
        String result = "对象信息:" + ot;
        System.out.println(result); // 输出:对象信息:OverrideToString{name='李四', id=1001}
    }
}

3. 实验结论

  • Object类默认的toString()方法返回格式为:全类名@哈希码(十六进制),其中哈希码由hashCode()方法(本地方法)生成。
  • 子类可重写toString()方法,自定义对象的字符串表示形式,便于调试和输出。
  • 在“+”字符串拼接运算中,对象会隐式调用toString()方法,将对象转换为字符串后再拼接。

(五)方法覆盖(Override)语法规则验证

1. 实验目的

验证方法覆盖的语法规则:访问范围、异常抛出、final方法、静态方法的限制。

2. 实验代码

// 父类
class ParentOverride {
    // 父类方法:public访问权限,抛出RuntimeException
    public void parentMethod() throws RuntimeException {
        System.out.println("Parent parentMethod");
    }

    // final方法,不可被覆盖
    public final void finalMethod() {
        System.out.println("Parent finalMethod");
    }

    // 静态方法,不可被覆盖(子类同名方法为隐藏,非覆盖)
    public static void staticMethod() {
        System.out.println("Parent staticMethod");
    }
}

// 子类
class ChildOverride extends ParentOverride {
    // 规则1:覆盖方法访问范围不能小于父类(public→public,合法)
    @Override
    public void parentMethod() throws RuntimeException {
        // 规则2:覆盖方法抛出的异常不能比父类多(父类抛RuntimeException,子类不抛或抛其子类,合法)
        System.out.println("Child parentMethod");
    }

    // 尝试覆盖final方法,编译错误
    // @Override
    // public void finalMethod() {
    //     System.out.println("Child finalMethod");
    // }

    // 静态方法:子类同名方法为隐藏,非覆盖(@Override注解会报错)
    public static void staticMethod() {
        System.out.println("Child staticMethod");
    }

    // 调用父类被覆盖的方法
    public void callParentMethod() {
        super.parentMethod(); // 通过super调用父类被覆盖的方法
    }
}

// 测试类
public class TestOverride {
    public static void main(String[] args) {
        ChildOverride co = new ChildOverride();
        co.parentMethod(); // 调用子类覆盖后的方法,输出:Child parentMethod
        co.callParentMethod(); // 调用父类方法,输出:Parent parentMethod

        // 静态方法:调用取决于变量类型,非对象类型(非多态)
        ParentOverride po = new ChildOverride();
        ParentOverride.staticMethod(); // 输出:Parent staticMethod
        ChildOverride.staticMethod(); // 输出:Child staticMethod
        po.staticMethod(); // 输出:Parent staticMethod(变量类型为ParentOverride)
    }
}

3. 实验结论

  • 方法覆盖要求子类与父类方法的签名(方法名、参数列表、返回值类型,其中返回值可为父类返回值的子类)完全一致。
  • 覆盖方法的访问权限不能小于父类(如父类为public,子类不能为protected/private)。
  • 覆盖方法抛出的异常不能比父类多(异常范围不能更大,可相同或为子类异常)。
  • final方法不可被覆盖,静态方法不可被覆盖(子类同名静态方法为“隐藏”,调用取决于变量类型,非对象类型)。
  • 子类中可通过super关键字调用父类被覆盖的方法。

二、多态相关实践验证

(一)多态核心特性验证(父类引用指向子类对象)

1. 实验目的

验证多态的核心特性:父类变量引用子类对象时,方法调用取决于对象的真实类型,字段访问取决于变量类型。

2. 实验代码

// 父类
class ParentPolymorphic {
    public int myValue = 100;

    public void printValue() {
        System.out.println("Parent.printValue(), myValue=" + myValue);
    }
}

// 子类
class ChildPolymorphic extends ParentPolymorphic {
    public int myValue = 200; // 隐藏父类字段

    @Override
    public void printValue() {
        System.out.println("Child.printValue(), myValue=" + myValue);
    }
}

// 测试类
public class ParentChildTest {
    public static void main(String[] args) {
        // 1. 父类对象调用方法和字段
        ParentPolymorphic parent = new ParentPolymorphic();
        parent.printValue(); // 输出:Parent.printValue(), myValue=100
        System.out.println("Parent myValue: " + parent.myValue); // 输出:Parent myValue: 100

        // 2. 子类对象调用方法和字段
        ChildPolymorphic child = new ChildPolymorphic();
        child.printValue(); // 输出:Child.printValue(), myValue=200
        System.out.println("Child myValue: " + child.myValue); // 输出:Child myValue: 200

        // 3. 父类引用指向子类对象(多态)
        ParentPolymorphic poly = new ChildPolymorphic();
        poly.printValue(); // 方法调用取决于对象真实类型(子类),输出:Child.printValue(), myValue=200
        System.out.println("Poly myValue: " + poly.myValue); // 字段访问取决于变量类型(父类),输出:Poly myValue: 100

        // 4. 修改父类字段(通过父类引用)
        poly.myValue++;
        System.out.println("After poly.myValue++, poly.myValue: " + poly.myValue); // 输出:101
        poly.printValue(); // 子类方法访问的是子类字段,输出:Child.printValue(), myValue=200

        // 5. 强制类型转换后访问子类字段
        ((ChildPolymorphic) poly).myValue++;
        System.out.println("After cast, Child myValue: " + ((ChildPolymorphic) poly).myValue); // 输出:201
        poly.printValue(); // 输出:Child.printValue(), myValue=201
    }
}

3. 实验结果

Parent.printValue(), myValue=100
Parent myValue: 100
Child.printValue(), myValue=200
Child myValue: 200
Child.printValue(), myValue=200
Poly myValue: 100
After poly.myValue++, poly.myValue: 101
Child.printValue(), myValue=200
After cast, Child myValue: 201
Child.printValue(), myValue=201

4. 实验结论

  • 多态场景下,方法调用遵循“动态绑定”:调用哪个方法由对象的真实类型决定(子类对象调用子类方法,父类对象调用父类方法)。
  • 字段访问遵循“静态绑定”:访问哪个字段由变量的声明类型决定(父类变量访问父类字段,子类变量访问子类字段,即使父类变量引用子类对象)。
  • 实际开发中应避免子类定义与父类同名的字段,避免字段隐藏导致的逻辑混乱。

(二)类型转换与instanceof验证

1. 实验目的

验证子类与父类对象的类型转换规则,以及instanceof运算符的作用。

2. 实验代码

// 基类
class Mammal {
}

// 子类1
class Dog extends Mammal {
}

// 子类2
class Cat extends Mammal {
}

// 测试类
public class TestCast {
    public static void main(String[] args) {
        Mammal m = null;
        Dog d = new Dog();
        Cat c = new Cat();

        // 1. 子类对象赋值给父类变量(自动类型转换,合法)
        m = d;
        System.out.println("m = d: 赋值成功(子类→父类)");

        // 2. 父类变量直接赋值给子类变量(编译错误,需强制转换)
        // d = m; 

        // 3. 父类变量强制转换为子类(m此时引用Dog对象,转换成功)
        d = (Dog) m;
        System.out.println("d = (Dog) m: 强制转换成功(m引用Dog对象)");

        // 4. 不同子类对象之间转换(编译错误,Dog和Cat无继承关系)
        // d = c; 

        // 5. 父类变量强制转换为无关子类(运行时错误,ClassCastException)
        m = new Mammal(); // m此时引用Mammal对象
        try {
            c = (Cat) m;
        } catch (ClassCastException e) {
            System.out.println("c = (Cat) m: 运行时错误," + e.getMessage());
        }

        // 6. instanceof运算符:判断对象是否可转换为指定类型
        Object obj1 = new Dog();
        Object obj2 = new Cat();
        Object obj3 = new Mammal();

        System.out.println("obj1 instanceof Dog: " + (obj1 instanceof Dog)); // true
        System.out.println("obj1 instanceof Mammal: " + (obj1 instanceof Mammal)); // true
        System.out.println("obj2 instanceof Cat: " + (obj2 instanceof Cat)); // true
        System.out.println("obj2 instanceof Dog: " + (obj2 instanceof Dog)); // false
        System.out.println("obj3 instanceof Cat: " + (obj3 instanceof Cat)); // false
    }
}

3. 实验结果

m = d: 赋值成功(子类→父类)
d = (Dog) m: 强制转换成功(m引用Dog对象)
c = (Cat) m: 运行时错误,class com.example.Mammal cannot be cast to class com.example.Cat
obj1 instanceof Dog: true
obj1 instanceof Mammal: true
obj2 instanceof Cat: true
obj2 instanceof Dog: false
obj3 instanceof Cat: false

4. 实验结论

  • 自动类型转换:子类对象可直接赋值给父类变量(向上转型),无需强制转换。
  • 强制类型转换:父类变量赋值给子类变量时,必须进行强制转换;若父类变量引用的对象不是目标子类的实例,运行时会抛出ClassCastException
  • instanceof运算符:用于判断对象是否为指定类(或其子类)的实例,返回boolean值;可在强制转换前使用,避免ClassCastException
  • 无继承关系的类之间不能相互转换(编译错误)。

(三)多态实际应用:动物园喂食场景重构

1. 实验目的

通过重构动物园喂食程序,验证多态在代码扩展性、可维护性上的优势。

2. 版本一:无多态(硬编码)

// 狮子类
class Lion {
    public void eat() {
        System.out.println("狮子吃鲜肉");
    }
}

// 猴子类
class Monkey {
    public void eat() {
        System.out.println("猴子吃香蕉");
    }
}

// 鸽子类
class Pigeon {
    public void eat() {
        System.out.println("鸽子吃谷物");
    }
}

// 饲养员类(硬编码,每个动物对应一个喂食方法)
class FeederV1 {
    private String name;

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

    public void feedLion(Lion lion) {
        System.out.print(name + "喂养:");
        lion.eat();
    }

    public void feedMonkey(Monkey monkey) {
        System.out.print(name + "喂养:");
        monkey.eat();
    }

    public void feedPigeon(Pigeon pigeon) {
        System.out.print(name + "喂养:");
        pigeon.eat();
    }
}

// 测试类
public class ZooV1 {
    public static void main(String[] args) {
        FeederV1 feeder = new FeederV1("小李");
        // 喂养1只狮子
        feeder.feedLion(new Lion());
        // 喂养10只猴子
        for (int i = 0; i < 10; i++) {
            feeder.feedMonkey(new Monkey());
        }
        // 喂养5只鸽子
        for (int i = 0; i < 5; i++) {
            feeder.feedPigeon(new Pigeon());
        }
    }
}

问题:若新增动物(如老虎),需修改Feeder类,新增feedTiger()方法,违反“开闭原则”(对扩展开放,对修改关闭)。

3. 版本二:基于继承的多态(重构后)

// 抽象动物类(基类)
abstract class Animal {
    public abstract void eat();
}

// 狮子类(继承Animal)
class LionV2 extends Animal {
    @Override
    public void eat() {
        System.out.println("狮子吃鲜肉");
    }
}

// 猴子类(继承Animal)
class MonkeyV2 extends Animal {
    @Override
    public void eat() {
        System.out.println("猴子吃香蕉");
    }
}

// 鸽子类(继承Animal)
class PigeonV2 extends Animal {
    @Override
    public void eat() {
        System.out.println("鸽子吃谷物");
    }
}

// 饲养员类(多态,一个方法处理所有动物)
class FeederV2 {
    private String name;

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

    // 接收Animal类型参数,可处理所有Animal子类对象
    public void feedAnimal(Animal animal) {
        System.out.print(name + "喂养:");
        animal.eat(); // 多态:调用子类的eat()方法
    }

    // 批量喂养(接收Animal数组)
    public void feedAnimals(Animal[] animals) {
        for (Animal animal : animals) {
            feedAnimal(animal);
        }
    }

    // 批量喂养(接收Vector集合,支持动态增减)
    public void feedAnimals(Vector<Animal> animals) {
        for (Animal animal : animals) {
            feedAnimal(animal);
        }
    }
}

// 测试类
public class ZooV2 {
    public static void main(String[] args) {
        FeederV2 feeder = new FeederV2("小李");

        // 方式1:单个喂养
        feeder.feedAnimal(new LionV2());

        // 方式2:数组批量喂养
        Animal[] animalArray = new Animal[16];
        animalArray[0] = new LionV2();
        for (int i = 0; i < 10; i++) {
            animalArray[1 + i] = new MonkeyV2();
        }
        for (int i = 0; i < 5; i++) {
            animalArray[11 + i] = new PigeonV2();
        }
        feeder.feedAnimals(animalArray);

        // 方式3:Vector动态喂养(支持新增/删除动物)
        Vector<Animal> animalVector = new Vector<>();
        animalVector.add(new LionV2()); // 新增狮子
        for (int i = 0; i < 10; i++) {
            animalVector.add(new MonkeyV2()); // 新增猴子
        }
        animalVector.remove(0); // 删除第一只狮子(动态调整)
        feeder.feedAnimals(animalVector);

        // 新增动物(如老虎),无需修改Feeder类
        class Tiger extends Animal {
            @Override
            public void eat() {
                System.out.println("老虎吃鲜肉");
            }
        }
        feeder.feedAnimal(new Tiger()); // 直接使用,无需修改Feeder
    }
}

4. 实验结论

  • 多态通过“父类引用指向子类对象”,使代码具备良好的扩展性:新增子类(如Tiger)时,无需修改已有代码(如Feeder类),只需新增子类并实现抽象方法。
  • 多态减少了代码冗余:将多个相似方法(feedLion()feedMonkey())合并为一个通用方法(feedAnimal())。
  • 结合集合(如Vector)使用时,可动态管理对象(新增/删除),进一步提升代码灵活性。

三、抽象类与接口实践验证

(一)抽象类与抽象方法验证

1. 实验目的

验证抽象类不能实例化、抽象方法必须由子类实现的规则。

2. 实验代码

// 抽象类(包含抽象方法和非抽象方法)
abstract class Person {
    private String name;

    // 非抽象方法
    public Person(String name) {
        this.name = name;
    }

    // 抽象方法(无实现)
    public abstract String getDescription();

    // 非抽象方法
    public String getName() {
        return name;
    }
}

// 子类实现抽象方法
class Employee extends Person {
    private String department;

    public Employee(String name, String department) {
        super(name); // 调用父类构造方法
        this.department = department;
    }

    // 实现父类的抽象方法
    @Override
    public String getDescription() {
        return "员工" + getName() + ",所属部门:" + department;
    }
}

// 子类未完全实现抽象方法(仍为抽象类)
abstract class Student extends Person {
    private String studentId;

    public Student(String name, String studentId) {
        super(name);
        this.studentId = studentId;
    }

    // 未实现getDescription(),因此Student仍为抽象类
    public String getStudentId() {
        return studentId;
    }
}

// 测试类
public class TestAbstract {
    public static void main(String[] args) {
        // 抽象类不能实例化,编译错误
        // Person p = new Person("张三");

        // 抽象类变量引用子类对象(多态)
        Person emp = new Employee("李四", "研发部");
        System.out.println(emp.getDescription()); // 输出:员工李四,所属部门:研发部

        // 未完全实现抽象方法的子类不能实例化,编译错误
        // Student stu = new Student("王五", "2023001");
    }
}

3. 实验结论

  • 抽象类(用abstract修饰)不能直接实例化,只能通过其子类实例化(子类需完全实现抽象方法)。
  • 包含抽象方法(用abstract修饰,无方法体)的类必须是抽象类;抽象类可包含非抽象方法和成员变量。
  • 子类继承抽象类后,必须实现父类的所有抽象方法,否则子类仍需声明为抽象类。
  • 抽象类的主要作用是作为基类,定义子类的共同行为(抽象方法),实现代码复用和多态。

(二)接口实践与特性验证

1. 实验目的

验证接口的定义、实现、多实现、接口继承等特性,以及接口与抽象类的区别。

2. 实验代码

// 接口1:可食用
interface IFood {
    // 接口方法默认public abstract,无需显式声明
    void cook();

    // 接口常量默认public static final
    String FOOD_TYPE = "可食用物品";
}

// 接口2:会游泳(继承IFood接口)
interface ISwim extends IFood {
    void swim();
}

// 抽象类:鸟
abstract class Bird {
    public void fly() {
        System.out.println("鸟会飞");
    }

    public abstract void layEggs(); // 抽象方法
}

// 鸭子类:继承Bird,实现ISwim接口(多实现)
class Duck implements ISwim {
    @Override
    public void cook() {
        System.out.println("鸭子可以烹饪(如烤鸭)");
    }

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

// 测试类
public class TestInterface {
    public static void main(String[] args) {
        // 接口变量引用实现类对象(多态)
        IFood food = new Duck();
        food.cook(); // 输出:鸭子可以烹饪(如烤鸭)
        System.out.println("食物类型:" + IFood.FOOD_TYPE); // 访问接口常量

        ISwim swim = new Duck();
        swim.swim(); // 输出:鸭子会游泳
        swim.cook(); // 实现了父接口IFood,可调用cook()

        // 接口与抽象类的区别:鸭子同时是Bird(继承)和IFood/ISwim(实现),实现多特性
        Duck duck = new Duck();
        duck.fly(); // 继承Bird的方法,输出:鸟会飞
        duck.swim(); // 实现ISwim的方法
        duck.cook(); // 实现IFood的方法
    }
}

3. 实验结论

  • 接口(用interface修饰)是方法声明的集合,方法默认public abstract,常量默认public static final
  • 类实现接口(用implements)时,必须实现接口的所有方法;一个类可实现多个接口(多实现),解决Java单继承的限制。
  • 接口可继承接口(用extends),子接口包含父接口的所有方法;实现子接口的类需实现父接口和子接口的所有方法。
  • 接口与抽象类的区别:
    • 抽象类是“不完全的类”,可包含非抽象方法和成员变量;接口仅包含方法声明和常量,无实现细节。
    • 一个类只能继承一个抽象类,但可实现多个接口。
    • 抽象类用于定义类的继承关系(IS-A),接口用于定义类的行为特性(CAN-DO)。

四、总结

本次实践围绕Java继承与多态的核心知识点,通过代码验证了以下关键结论:

  1. 继承:子类通过extends继承父类,自动拥有父类的public/protected成员;构造方法调用需遵循super关键字规则;final类不可继承、final方法不可覆盖、final变量不可修改。
  2. 多态:核心是“父类引用指向子类对象”,方法调用动态绑定(取决于对象真实类型),字段访问静态绑定(取决于变量类型);多态显著提升代码的扩展性和可维护性。
  3. 抽象类与接口:抽象类不能实例化,用于定义子类共同行为;接口用于定义类的行为特性,支持多实现,解决单继承限制。
  4. 访问权限:public、private、protected、default的作用范围决定了继承中成员的可访问性,是封装特性的重要体现。

通过动手实践,深入理解了Java面向对象的核心机制,为后续开发中合理设计类结构、灵活运用多态奠定了基础。

posted @ 2025-10-26 17:55  20243867孙堃2405-2  阅读(33)  评论(0)    收藏  举报