【Java SE】继承与多态

发布时间:2026/7/10 15:42:12
【Java SE】继承与多态 文章目录一、 继承Inheritance1.1 为什么需要继承1.2 继承的概念1.3 继承的语法1.4 父类成员访问1.5 super关键字1.6 子类构造方法1.7 初始化顺序1.8 访问权限与继承1.9 继承方式1.10 final关键字1.11 继承与组合二、 多态Polymorphism2.1 多态的概念2.2 多态的实现条件2.3 方法重写Override2.4 向上转型与向下转型2.5 多态的优缺点2.6 避免在构造方法中调用重写方法一、 继承Inheritance1.1 为什么需要继承在现实世界中许多对象之间存在共性。例如狗和猫都是动物它们共享一些基本特征如名字、年龄和体重以及行为如吃饭和睡觉。如果在代码中为每个类单独定义这些共性的属性和方法会导致大量重复代码增加维护成本。继承机制允许我们抽取这些共性形成父类基类让子类派生类继承父类的特征并添加自己特有的属性和方法。这样不仅减少了代码冗余也提高了代码的可维护性和可读性。继承主要解决的问题是共性的抽取实现代码复用。1.2 继承的概念继承是面向对象程序设计使代码可以复用的最重要手段它允许程序员在保持原有类特性的基础上进行扩展增加新功能。这样产生的新类称为派生类。继承呈现了面向对象程序设计的层次结构体现了由简单到复杂的认知过程。例如我们可以创建一个Animal类作为父类然后让Dog和Cat类继承它classAnimal{Stringname;intage;publicvoideat(){System.out.println(name正在吃饭);}publicvoidsleep(){System.out.println(name正在睡觉);}}classDogextendsAnimal{voidbark(){System.out.println(name汪汪汪);}}classCatextendsAnimal{voidmew(){System.out.println(name喵喵喵);}}1.3 继承的语法在Java中使用extends关键字实现继承classSubClassextendsSuperClass{// 子类特有的属性和方法}1.4 父类成员访问在继承体系中子类可以访问父类的非私有成员属性和方法。访问规则子类和父类不存在同名成员变量子类可以直接访问父类的成员变量子类和父类成员变量同名遵循就近原则优先访问子类自己的成员变量classBase{inta10;intb20;}classDerivedextendsBase{inta30;// 与父类成员变量同名voiddisplay(){System.out.println(a);// 输出30子类的aSystem.out.println(super.a);// 输出10父类的aSystem.out.println(b);// 输出20父类的b}}1.5 super关键字super关键字用于在子类中访问父类的成员特别是在存在同名成员时classDerivedextendsBase{inta;voidmethod(){super.a100;// 访问父类的aa200;// 访问子类的asuper.method();// 调用父类的方法}}1.6 子类构造方法子类构造时必须先调用父类构造方法确保父类成员先初始化若父类显式定义无参或者默认的构造方法在子类构造方法第一行默认有隐含的super()调用即调用父类构造方法如果父类构造方法是带有参数的此时需要用户为子类显式定义构造方法并在子类构造方法中选择合适的父类构造方法调用否则编译失败。在子类构造方法中super(...)调用父类构造时必须是子类构造函数中第一条语句。super(...)只能在子类构造方法中出现一次并且不能和this同时出现classBase{publicBase(){System.out.println(Base构造函数);}}classDerivedextendsBase{publicDerived(){super();//可省略System.out.println(Derived构造函数);}}1.7 初始化顺序父类静态代码块子类静态代码块静态代码块只执行一次父类实例代码块父类构造方法子类实例代码块子类构造方法classParent{static{System.out.println(父类静态代码块);}{System.out.println(父类实例代码块);}publicParent(){System.out.println(父类构造方法);}}classChildextendsParent{static{System.out.println(子类静态代码块);}{System.out.println(子类实例代码块);}publicChild(){System.out.println(子类构造方法);}}// 测试代码publicclassTest{publicstaticvoidmain(String[]args){Childc1newChild();System.out.println();Childc2newChild();}}输出结果题目以下程序的输出结果是classX{YynewY();//1publicX(){//2System.out.print(X);}}classY{publicY(){//3System.out.print(Y);}}publicclassZextendsX{YynewY();//4publicZ(){//5System.out.print(Z);}publicstaticvoidmain(String[]args){newZ();}}首先我们要明确执行顺序是父类静态代码-子类静态代码-父类实例代码-子类实例代码-父类构造函数-子类构造函数这段代码中没有静态代码,先找父类的实例代码(1和2),这里1输出Y,2输出x接着执行子类的实例代码(4和5),4输出Y,5输出Z因此输出结果为YXYZ1.8 访问权限与继承Java中的访问修饰符影响继承关系中成员的可见性修饰符同一包中子类不同包中子类不同包非子类private❌❌❌default✅❌❌protected✅✅❌public✅✅✅需要注意的是父类的private成员虽然不能被直接访问但仍然被继承到子类中。1.9 继承方式Java支持以下几种继承方式单继承一个子类只能有一个直接父类多层继承例如A → B → C不同类继承同一父类例如B → AC → A❌不支持多继承如C extends A, B1.10 final关键字final关键字用于限制继承final修饰变量常量不可修改final修饰方法不可重写final修饰类不可继承如String类finalclassFinalClass{// 这个类不能被继承}classChildextendsFinalClass{// 编译错误}1.11 继承与组合继承表示is a关系如狗是动物组合表示a part of关系如汽车有发动机示例组合// 轮胎类classTire{// ...}// 发动机类classEngine{// ...}// 车载系统类classVehicleSystem{// ...}classCar{privateTiretire;// 可以复用轮胎中的属性和方法privateEngineengine;// 可以复用发动机中的属性和方法privateVehicleSystemvs;// 可以复用车载系统中的属性和方法// ...}继承classBenzextendCar{// 将汽车中包含的轮胎、发送机、车载系统全部继承下来}在实际开发中应优先使用组合而非继承因为组合提供了更好的灵活性和更低的耦合度。二、 多态Polymorphism2.1 多态的概念多态是指同一行为在不同对象上表现出不同状态。它是面向对象编程的核心特性之一允许我们使用统一的接口处理不同类型的对象。2.2 多态的实现条件在Java中实现多态需要满足以下条件必须在继承体系下子类必须重写父类方法通过父类的引用调用重写的方法classAnimal{publicvoidmakeSound(){System.out.println(动物发出声音);}}classDogextendsAnimal{OverridepublicvoidmakeSound(){System.out.println(汪汪汪);}}classCatextendsAnimal{OverridepublicvoidmakeSound(){System.out.println(喵喵喵);}}publicclassTest{publicstaticvoidmain(String[]args){AnimalmyAnimalnewAnimal();AnimalmyDognewDog();AnimalmyCatnewCat();myAnimal.makeSound();// 输出: 动物发出声音myDog.makeSound();// 输出: 汪汪汪myCat.makeSound();// 输出: 喵喵喵}}2.3 方法重写Override方法重写是实现多态的基础必须满足以下规则方法名、参数列表顺序类型个数相同返回值类型相同或为父类返回值的子类访问权限不能比父类更严格可放宽不能重写static、private、final方法使用Override注解可以帮助编译器检查重写是否正确classParent{protectedvoidshow(){System.out.println(Parent的show方法);}}classChildextendsParent{Override// 确保这是重写而不是重载publicvoidshow(){// 访问权限从protected变为public放宽System.out.println(Child的show方法);}}与重载的区别:区别点重写(override)重载(override)参数列表不能修改必须修改返回类型不能修改【除非可以构成父子类关系】 可以修改访问限定符不能做更严格的限制可以降低限制 可以修改2.4 向上转型与向下转型向上转型Upcasting是子类对象赋给父类引用这是安全的且会自动进行AnimalanimalnewDog();// 向上转型注意父类引用不可以直接调用子类特有的方法这也是向上转型的缺点animal.bark()//错误向下转型Downcasting是父类引用转回子类类型需要显式转换且可能失败AnimalanimalnewDog();Dogdog(Dog)animal;// 向下转型向下转型可能抛出ClassCastException因此应该先使用instanceof进行检查if(animalinstanceofDog){Dogdog(Dog)animal;dog.bark();}2.5 多态的优缺点优点提高代码的可扩展性和可维护性减少代码的圈复杂度减少if-else语句实现接口与实现的分离缺点性能略有下降动态绑定需要运行时确定方法无法直接访问子类特有的成员2.6 避免在构造方法中调用重写方法在构造方法中调用可重写的方法可能导致意想不到的行为因为子类可能还没有完全初始化classParent{publicParent(){show();// 危险可能调用子类重写的方法}publicvoidshow(){System.out.println(Parent的show方法);}}classChildextendsParent{privateintvalue10;Overridepublicvoidshow(){System.out.println(Child的show方法value value);}}publicclassTest{publicstaticvoidmain(String[]args){ChildchildnewChild();// 输出: Child的show方法value 0}}在上面的例子中value的值为0而不是10因为父类构造函数调用show()时子类的初始化还没有完成。