第6篇:Java面向对象进阶:继承、重写与多态,解锁代码复用新姿势
上一篇我们掌握了Java面向对象基础学会了定义类、创建对象用封装保护数据安全用构造方法简化对象初始化完成了面向对象版的学生成绩管理案例。但在实际开发中我们会遇到“多个类拥有相同属性和方法”的场景——比如“学生类”“老师类”“管理员类”都拥有“姓名、年龄”等属性和“展示信息”等方法如果每个类都重复定义这些相同的内容会导致代码冗余、维护困难。而Java面向对象的三大特性封装、继承、多态中继承正是为解决“代码复用”而生方法重写让子类能个性化扩展父类功能多态则让代码更具灵活性和扩展性三者相辅相成是Java进阶的核心也是面试高频考点。本篇文章将从基础入手手把手教你理解继承的概念、用法与优势掌握方法重载与重写的区别吃透多态的实现条件与应用场景拆解新手高频易错点结合实战案例让你彻底掌握面向对象进阶技巧编写更简洁、更具扩展性的代码。核心目标理解继承的本质与作用掌握继承的定义与使用能区分方法重载与重写理解多态的核心原理与实现条件熟练运用继承、重写、多态完成实战案例规避常见坑掌握相关面试考点为后续学习接口、抽象类筑牢基础。一、前置认知为什么需要继承解决代码冗余问题在学习继承之前我们先看一个场景定义“学生类Student”和“老师类Teacher”两个类的代码如下// 学生类 public class Student { // 成员变量 private String name; private int age; // 构造方法 public Student() {} public Student(String name, int age) { this.name name; this.age age; } // 成员方法 public String getName() { return name; } public void setName(String name) { this.name name; } public int getAge() { return age; } public void setAge(int age) { this.age age; } // 展示信息 public void showInfo() { System.out.println(姓名 name 年龄 age); } // 学生特有方法 public void study() { System.out.println(name 正在学习); } } // 老师类 public class Teacher { // 成员变量和Student类完全相同 private String name; private int age; // 构造方法和Student类完全相同 public Teacher() {} public Teacher(String name, int age) { this.name name; this.age age; } // 成员方法和Student类完全相同 public String getName() { return name; } public void setName(String name) { this.name name; } public int getAge() { return age; } public void setAge(int age) { this.age age; } // 展示信息和Student类完全相同 public void showInfo() { System.out.println(姓名 name 年龄 age); } // 老师特有方法 public void teach() { System.out.println(name 正在授课); } }观察代码不难发现Student类和Teacher类有大量重复代码成员变量、构造方法、showInfo方法这就是“代码冗余”。如果后续还要定义“管理员类”“辅导员类”会重复编写更多相同代码不仅开发效率低后续修改时比如修改showInfo方法的格式还需要修改所有类的代码维护成本极高。而继承就能完美解决这个问题我们可以提取多个类的“共性内容”定义一个“父类”比如“Person类”将相同的属性和方法放在父类中然后让Student类、Teacher类“继承”父类这样子类就会自动拥有父类的所有属性和方法无需重复定义只需编写子类特有的属性和方法即可。核心结论继承的核心作用是代码复用减少冗余代码提高开发效率同时让类与类之间产生关联为后续多态的实现奠定基础。二、核心知识点继承Inheritance的定义与使用继承是面向对象的三大特性之一本质是“子类继承父类的属性和方法”子类可以直接使用父类中非private修饰的属性和方法同时可以定义自己特有的属性和方法实现功能的扩展。类比理解儿子继承父亲的财产相当于子类继承父类的属性和方法同时儿子可以有自己的财产和技能相当于子类特有的属性和方法。2.1 继承的核心概念父类超类、基类提取多个子类的共性内容是子类的“模板”比如上面的Person类子类派生类继承父类的属性和方法同时可以扩展自己的特有功能比如Student类、Teacher类继承关系子类与父类之间是“is a”的关系子类是父类的一种比如Student is a Person学生是人的一种Teacher is a Person老师是人的一种。2.2 继承的定义格式固定写法必须掌握Java中用extends关键字实现继承格式如下// 父类定义普通类 public class 父类名 { // 共性属性和方法 } // 子类定义继承父类 public class 子类名 extends 父类名 { // 子类特有属性和方法可选 }关键说明Java只支持单继承一个子类只能继承一个父类不支持多继承比如子类不能同时继承Person和Animal但支持多层继承比如Student继承PersonPrimaryStudent继承Student子类会继承父类中所有非private修饰的属性和方法private修饰的属性和方法子类无法直接访问需通过父类的getter/setter方法访问子类不能继承父类的构造方法但可以通过super关键字调用父类的构造方法后续讲解。2.3 继承实战案例解决代码冗余提取Person类作为父类封装共性属性和方法让Student类、Teacher类继承Person类简化代码// 父类Person类共性内容 public class Person { // 共性成员变量private修饰通过getter/setter访问 private String name; private int age; // 共性构造方法 public Person() {} public Person(String name, int age) { this.name name; this.age age; } // 共性getter/setter方法 public String getName() { return name; } public void setName(String name) { this.name name; } public int getAge() { return age; } public void setAge(int age) { this.age age; } // 共性方法展示信息 public void showInfo() { System.out.println(姓名 name 年龄 age); } } // 子类Student类继承Person类 public class Student extends Person { // 子类特有属性可选 private double score; // 子类构造方法需调用父类构造方法 public Student() {} // 有参构造调用父类的有参构造初始化共性属性再初始化子类特有属性 public Student(String name, int age, double score) { super(name, age); // super关键字调用父类的有参构造方法 this.score score; } // 子类特有getter/setter方法 public double getScore() { return score; } public void setScore(double score) { this.score score; } // 子类特有方法 public void study() { // 子类可以调用父类的非private方法showInfo showInfo(); System.out.println(getName() 正在学习成绩 score); } } // 子类Teacher类继承Person类 public class Teacher extends Person { // 子类特有属性 private double salary; // 子类构造方法 public Teacher() {} public Teacher(String name, int age, double salary) { super(name, age); // 调用父类有参构造 this.salary salary; } // 子类特有getter/setter方法 public double getSalary() { return salary; } public void setSalary(double salary) { this.salary salary; } // 子类特有方法 public void teach() { showInfo(); System.out.println(getName() 正在授课月薪 salary 元); } } // 测试类 public class InheritanceTest { public static void main(String[] args) { // 创建Student对象 Student student new Student(张三, 18, 90.5); // 调用父类的方法showInfo student.showInfo(); // 调用子类的特有方法 student.study(); System.out.println(-------------------); // 创建Teacher对象 Teacher teacher new Teacher(李老师, 35, 8000); teacher.showInfo(); teacher.teach(); // 调用父类的getter方法 System.out.println(老师姓名 teacher.getName()); // 调用子类的getter方法 System.out.println(老师月薪 teacher.getSalary()); } }运行结果姓名张三年龄18 姓名张三年龄18 张三正在学习成绩90.5 ------------------- 姓名李老师年龄35 姓名李老师年龄35 李老师正在授课月薪8000.0元 老师姓名李老师 老师月薪8000.0核心优势通过继承Student类和Teacher类无需重复定义name、age属性和showInfo方法只需编写特有属性和方法代码冗余大幅减少后续修改共性内容比如修改showInfo方法只需修改父类代码所有子类都会同步生效维护成本大大降低。2.4 继承中的super关键字重点super关键字的核心作用是“访问父类的成员”主要用于3种场景是继承中不可或缺的关键字1调用父类的构造方法子类的构造方法中默认会隐含调用父类的无参构造方法super();如果父类没有无参构造方法手动定义了有参构造则必须手动用super()调用父类的有参构造方法否则会报错。关键规则super()必须写在子类构造方法的第一行否则报错且只能出现一次。// 父类只有有参构造无无参构造 public class Person { private String name; private int age; // 手动定义有参构造Java不再提供默认无参构造 public Person(String name, int age) { this.name name; this.age age; } } // 子类必须手动调用父类的有参构造 public class Student extends Person { private double score; // 错误未调用父类有参构造报错 // public Student(String name, int age, double score) { // this.score score; // } // 正确手动调用父类有参构造super()写在第一行 public Student(String name, int age, double score) { super(name, age); // 调用父类有参构造初始化name和age this.score score; } }2调用父类的成员方法当子类的方法与父类的方法重名时方法重写用super.方法名()调用父类的方法区分子类和父类的同名方法。public class Person { public void showInfo() { System.out.println(我是父类的showInfo方法); } } public class Student extends Person { // 方法重写子类方法与父类方法同名 Override public void showInfo() { super.showInfo(); // 调用父类的showInfo方法 System.out.println(我是子类的showInfo方法); } }3调用父类的成员变量当子类的成员变量与父类的成员变量重名时用super.成员变量名访问父类的成员变量类似this关键字的用法。public class Person { protected String name 父类姓名; // protected修饰子类可直接访问 } public class Student extends Person { private String name 子类姓名; public void showName() { System.out.println(父类姓名 super.name); // 访问父类成员变量 System.out.println(子类姓名 this.name); // 访问子类成员变量 } }2.5 .继承的常见易错点新手必看Java支持多继承错误Java只支持单继承一个子类只能继承一个父类子类继承父类的构造方法错误子类不能继承父类的构造方法只能通过super关键字调用super()的位置错误super()必须写在子类构造方法的第一行否则报错父类有参构造未手动调用父类手动定义有参构造后子类未用super()调用导致报错子类访问父类private成员试图直接访问父类private修饰的属性/方法导致报错需通过父类getter/setter访问。三、易混淆知识点方法重载Overloadvs 方法重写Override方法重载和方法重写是Java中两个极易混淆的概念二者都涉及“方法同名”但作用、实现条件完全不同是新手高频易错点也是面试高频考点必须严格区分。3.1 方法重载Overload同一类中的“同名不同参”方法重载的核心是“在同一个类中定义多个同名方法但参数列表不同”用于实现“同一功能的不同实现方式”比如求和可实现两个int求和、两个double求和。方法重载的实现条件必须同时满足方法名必须完全相同大小写一致参数列表必须不同至少满足以下一种参数个数不同比如sum(int a) 和 sum(int a, int b)参数类型不同比如sum(int a, int b) 和 sum(double a, double b)参数顺序不同比如sum(int a, double b) 和 sum(double a, int b)返回值类型、访问权限可以不同不影响重载。方法重载实战案例public class Calculator { // 方法1两个int求和 public int sum(int a, int b) { return a b; } // 方法2三个int求和参数个数不同重载 public int sum(int a, int b, int c) { return a b c; } // 方法3两个double求和参数类型不同重载 public double sum(double a, double b) { return a b; } // 方法4int和double求和参数顺序不同重载 public double sum(int a, double b) { return a b; } // 错误参数列表相同仅返回值不同不是重载报错 // public double sum(int a, int b) { // return a b; // } public static void main(String[] args) { Calculator calc new Calculator(); System.out.println(calc.sum(10, 20)); // 调用sum(int, int) System.out.println(calc.sum(10, 20, 30)); // 调用sum(int, int, int) System.out.println(calc.sum(10.5, 20.5)); // 调用sum(double, double) System.out.println(calc.sum(10, 20.5)); // 调用sum(int, double) } }3.2 方法重写Override子类与父类的“同名同参”方法重写的核心是“子类继承父类后定义与父类同名、同参数列表的方法”用于“修改或扩展父类方法的功能”比如父类showInfo方法展示基础信息子类重写后展示更多信息。方法重写也叫“方法覆盖”必须满足“子类方法与父类方法完全匹配”除了方法体。方法重写的实现条件必须同时满足面试重点方法名必须完全相同大小写一致参数列表必须完全相同参数个数、类型、顺序都相同返回值类型子类方法的返回值类型必须小于等于父类方法的返回值类型新手可简单记“相同或子类”访问权限子类方法的访问权限必须大于等于父类方法的访问权限比如父类方法是protected子类方法可以是protected或public不能是private父类方法不能是private修饰private修饰的方法子类无法继承无法重写子类方法不能添加static关键字父类方法是static子类方法也必须是static这不是重写是静态方法的隐藏。关键提醒重写方法时建议添加Override注解注解用于标记重写方法IDE会自动检查重写条件是否满足避免写错。方法重写实战案例// 父类Person public class Person { protected void showInfo() { System.out.println(父类姓名 getName() 年龄 getAge()); } // private方法子类无法重写 private void eat() { System.out.println(父类吃饭); } // static方法子类不能重写只能隐藏 public static void sleep() { System.out.println(父类睡觉); } // getter方法省略setter public String getName() { return 未知姓名; } public int getAge() { return 0; } } // 子类Student重写父类方法 public class Student extends Person { private double score; // 重写父类的showInfo方法Override注解标记 Override protected void showInfo() { // 调用父类的showInfo方法保留父类功能 super.showInfo(); // 扩展子类特有功能 System.out.println(子类学生成绩 score); } // 错误父类eat()是private无法重写报错 // Override // private void eat() { // System.out.println(子类吃饭); // } // 不是重写父类sleep()是static子类也写static是静态方法隐藏 public static void sleep() { System.out.println(子类睡觉); } // 重写父类的getName方法返回值类型相同 Override public String getName() { return 张三; } // setter/getter省略 public double getScore() { return score; } public void setScore(double score) { this.score score; } } // 测试类 public class OverrideTest { public static void main(String[] args) { Student student new Student(); student.setScore(90.5); // 调用重写后的showInfo方法子类方法 student.showInfo(); // 调用重写后的getName方法子类方法 System.out.println(学生姓名 student.getName()); // 调用静态方法子类隐藏父类方法用子类名调用 Student.sleep(); // 调用父类静态方法用父类名调用 Person.sleep(); } }运行结果父类姓名张三年龄0 子类学生成绩90.5 学生姓名张三 子类睡觉 父类睡觉3.3 方法重载与方法重写的核心区别面试必背区别维度方法重载Overload方法重写Override定义位置同一个类中子类与父类之间继承关系方法名相同相同参数列表不同个数、类型、顺序相同个数、类型、顺序返回值类型可不同相同或子类小于等于父类访问权限可不同子类≥父类核心作用同一功能的不同实现方式修改/扩展父类方法的功能关键字无特殊关键字Override注解推荐口诀记忆新手必记重载看参数同名不同参同一类重写看继承同名同参子类父类。四、面向对象核心特性多态Polymorphism多态是面向对象的三大特性之一也是Java进阶的核心难点核心思想是“同一方法不同对象有不同的实现”即“一个接口多种实现”。多态能让代码更具灵活性、扩展性是实际开发中常用的编程思想比如Spring框架的依赖注入核心就是多态。类比理解“动物叫”这个行为狗叫是“汪汪汪”猫叫是“喵喵喵”鸟叫是“叽叽叽”——同一个“叫”的方法不同的动物对象有不同的实现这就是多态。4.1 多态的实现条件必须同时满足面试重点多态的实现依赖3个条件缺一不可新手必须牢记存在继承关系子类继承父类子类重写父类的方法核心没有重写就没有多态父类引用指向子类对象核心语法父类名 引用名 new 子类名();。关键语法父类引用指向子类对象// 格式父类名 引用名 new 子类名(); Person student new Student(); // 父类Person引用指向子类Student对象 Person teacher new Teacher(); // 父类Person引用指向子类Teacher对象4.2 多态实战案例吃透核心结合继承和方法重写实现多态// 父类Animal动物类 public class Animal { // 父类方法被子类重写 public void cry() { System.out.println(动物在叫); } } // 子类Dog狗类继承Animal重写cry方法 public class Dog extends Animal { Override public void cry() { System.out.println(狗在叫汪汪汪~); } // 子类特有方法 public void eat() { System.out.println(狗在吃骨头); } } // 子类Cat猫类继承Animal重写cry方法 public class Cat extends Animal { Override public void cry() { System.out.println(猫在叫喵喵喵~); } } // 子类Bird鸟类继承Animal重写cry方法 public class Bird extends Animal { Override public void cry() { System.out.println(鸟在叫叽叽叽~); } } // 测试类多态实现 public class PolymorphismTest { public static void main(String[] args) { // 1. 父类引用指向子类对象多态核心语法 Animal animal1 new Dog(); Animal animal2 new Cat(); Animal animal3 new Bird(); // 2. 调用cry方法多态体现同一方法不同对象有不同实现 animal1.cry(); // 输出狗在叫汪汪汪~调用Dog的cry方法 animal2.cry(); // 输出猫在叫喵喵喵~调用Cat的cry方法 animal3.cry(); // 输出鸟在叫叽叽叽~调用Bird的cry方法 // 3. 多态的注意点父类引用不能直接调用子类特有方法 // animal1.eat(); // 错误Animal引用无法调用Dog的特有方法eat() // 解决方法向下转型将父类引用转为子类引用 if (animal1 instanceof Dog) { // 判断animal1是否是Dog类型的对象 Dog dog (Dog) animal1; // 向下转型 dog.eat(); // 可以调用子类特有方法 } } }运行结果狗在叫汪汪汪~ 猫在叫喵喵喵~ 鸟在叫叽叽叽~ 狗在吃骨头4.3 多态的核心细节新手必懂1多态的核心父类引用调用重写方法时执行的是子类的方法当父类引用指向子类对象时调用的重写方法是“子类的方法”而不是父类的方法——这是多态的核心体现也是“同一方法不同实现”的本质。比如上面的animal1.cry()animal1是Animal类型的引用但指向的是Dog对象所以执行的是Dog类的cry方法而不是Animal类的cry方法。2多态的限制父类引用不能直接调用子类特有方法父类引用只能访问父类中定义的属性和方法无法直接访问子类特有的属性和方法比如Animal引用无法调用Dog的eat方法。如果需要调用子类特有方法必须进行“向下转型”。3转型向上转型与向下转型重点多态中的转型分为两种类比“向上转型”是“自动类型转换”“向下转型”是“强制类型转换”和基本数据类型的转换类似。向上转型自动转型子类对象赋值给父类引用无需强制转换是多态的核心语法比如Dog dog new Dog(); Animal animal dog; 或直接Animal animal new Dog();向下转型强制转型父类引用转为子类引用需要强制转换比如Animal animal new Dog(); Dog dog (Dog) animal;转型前建议用instanceof关键字判断避免转型错误。instanceof关键字判断一个对象是否是某个类或其子类的实例返回boolean类型语法对象 instanceof 类名。Animal animal new Dog(); // 判断animal是否是Dog类的实例 if (animal instanceof Dog) { Dog dog (Dog) animal; // 转型成功 } // 判断animal是否是Cat类的实例false if (animal instanceof Cat) { Cat cat (Cat) animal; // 转型失败报错ClassCastException }4.4 多态的优势实际开发常用提高代码的灵活性同一方法不同对象有不同实现无需修改代码就能实现不同功能提高代码的扩展性新增子类时无需修改原有父类代码和测试代码只需让子类继承父类、重写方法即可比如新增Pig类只需重写cry方法就能直接用Animal引用调用降低代码的耦合度父类引用指向子类对象调用方法时无需关心具体是哪个子类对象只需关注父类接口简化代码逻辑。4.5 多态的常见易错点新手必看多态实现条件缺失缺少继承、方法重写、父类引用指向子类对象中的任意一个都无法实现多态父类引用调用子类特有方法直接用父类引用调用子类特有方法报错向下转型未判断未用instanceof判断就强制转型导致类型转换异常ClassCastException静态方法无法实现多态静态方法属于类不属于对象父类引用调用静态方法时执行的是父类的静态方法不是子类的。五、新手高频易错点总结必看避坑指南继承相关误以为Java支持多继承、子类继承父类构造方法、super()位置错误、父类有参构造未手动调用方法重载与重写混淆分不清“同名不同参”和“同名同参”重写时不满足条件比如返回值类型错误、访问权限不足多态相关多态实现条件缺失、父类引用调用子类特有方法、向下转型未用instanceof判断导致报错访问权限混淆子类无法访问父类private成员误以为protected修饰的成员在其他类中也能访问。六、总结本篇文章重点讲解了Java面向对象进阶的三大核心知识点——继承、方法重载与重写、多态这是Java进阶的关键也是面试高频考点。我们学会了用继承解决代码冗余用方法重写扩展父类功能用多态提高代码的灵活性和扩展性同时通过实战案例吃透了每个知识点的核心细节和易错点理解了面向对象思想的精髓。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2564937.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!