将子类对象存入父类数组后,如何调用子类专属方法?
解决Java父类数组调用子类专属方法的问题
嘿,这个问题是Java里向上转型后非常常见的场景——当你把子类对象存入父类型数组时,编译器只会把数组元素识别为父类Person类型,自然没法直接调用子类独有的showStudentInfo()和showEmployeeInfo()方法。咱们有两种靠谱的解决方式,一起来看看:
方式一:向下转型(强制类型转换)
既然数组里的对象实际是子类类型,那咱们可以先判断对象的真实类型,再把它强制转换成对应的子类类型,这样就能调用子类专属方法了。
修改后的Demo代码
public class Demo { public static void main(String[] args) { Person ivan = new Person("Ivan Georgiev", 27, true); Person nikola = new Person("Nikola Ivanov", 30, true); Student iskra = new Student("Iskra Dimitrova", 21, false, 4.5); Student georgi = new Student("Georgi Kazakov", 19, true, 5.5); Employee neli = new Employee("Anelia Stoicheva", 35, false, 50); Employee monika = new Employee("Monika Petrova", 42, false, 80); // 先计算加班工资,不然showEmployeeInfo里的extraSum会是默认0 neli.calculateOvertime(2); monika.calculateOvertime(3); Person[] array = new Person[6]; array[0] = ivan; array[1] = nikola; array[2] = iskra; array[3] = georgi; array[4] = neli; array[5] = monika; // 用增强for循环更简洁 for (Person person : array) { if (person instanceof Student) { // 向下转型为Student,调用子类方法 Student student = (Student) person; student.showStudentInfo(); } else if (person instanceof Employee) { // 向下转型为Employee,调用子类方法 Employee employee = (Employee) person; employee.showEmployeeInfo(); } else { // 父类Person对象,调用父类方法 person.showPersonInfo(); } } } }
关键点说明
- 用
instanceof关键字判断对象的实际类型,这比你原来用getClass().equals()更常用,也更灵活(它会考虑继承关系) - 转型后必须是对象的真实类型,不然会抛出
ClassCastException异常,所以一定要先判断再转型 - 额外提一句:你原来的
Employee类里的showEmployeeInfo()依赖extraSum,这个值需要调用calculateOvertime()才能生成,所以遍历前记得先调用这个方法赋值哦
方式二:利用多态(更优雅的方案)
如果想避免频繁的类型判断和转型,咱们可以利用Java的多态特性——在父类定义一个通用的方法,子类重写这个方法,这样遍历时直接调用父类方法就会自动触发子类的实现。
步骤1:修改父类Person,添加通用方法
public class Person { String name; int age; boolean isMan; Person(String name, int age, boolean isMan) { this.name = name; this.age = age; this.isMan = isMan; } // 定义通用的展示信息方法,子类重写 void showInfo() { System.out.println("Име: " + this.name + " | " + "години: " + this.age + " | " + "мъж ли е: " + this.isMan); } }
步骤2:子类重写showInfo方法
Student类:
public class Student extends Person { double score; Student(String name, int age, boolean isMan, double score) { super(name, age, isMan); this.score = score; } @Override public void showInfo() { // 修复你原来代码里多余的竖线问题 System.out.println("Име: " + super.name + " | " + "години: " + super.age + " | " + "мъж ли е: " + super.isMan + " | " + "Оценка: " + this.score); } }
Employee类:
public class Employee extends Person { double daySallary; double extraSum; Employee(String name, int age, boolean isMan, double daySallary){ super(name, age, isMan); this.daySallary=daySallary; } double calculateOvertime(double hours) { if (this.age < 18) extraSum = 0; else extraSum = (this.daySallary / 8) * hours * 1.5; return extraSum; } @Override public void showInfo() { // 同样修复多余竖线问题 System.out.println("Име: " + super.name + " | " + "години: " + super.age + " | " + "мъж ли е: " + super.isMan + " | " + "Допълнителна сума от оставане след работно време: " + this.extraSum); } }
步骤3:简化Demo的遍历代码
public class Demo { public static void main(String[] args) { Person ivan = new Person("Ivan Georgiev", 27, true); Person nikola = new Person("Nikola Ivanov", 30, true); Student iskra = new Student("Iskra Dimitrova", 21, false, 4.5); Student georgi = new Student("Georgi Kazakov", 19, true, 5.5); Employee neli = new Employee("Anelia Stoicheva", 35, false, 50); Employee monika = new Employee("Monika Petrova", 42, false, 80); neli.calculateOvertime(2); monika.calculateOvertime(3); Person[] array = new Person[6]; array[0] = ivan; array[1] = nikola; array[2] = iskra; array[3] = georgi; array[4] = neli; array[5] = monika; // 直接调用showInfo,多态会自动匹配子类实现 for (Person person : array) { person.showInfo(); } } }
这种方式的好处
- 完全不需要类型判断和转型,代码更简洁
- 符合开闭原则:以后新增子类时,只需要重写
showInfo()方法,不用修改遍历的逻辑,维护起来更轻松
另外,顺便提一下你原来代码里的小瑕疵:Student的showStudentInfo()方法里,"мъж ли е: "后面多了一个多余的" | ",会导致输出出现空的竖线段,我在上面的代码里已经修复了这个问题~
内容的提问来源于stack exchange,提问作者Nikolay Todorov
相关产品推荐
相关产品推荐

