前言 继承和多态是面向对象编程的重要特性,它们为代码重用和灵活设计提供了强大支持。继承允许我们基于现有类创建新类,实现代码复用;多态则让我们能够用统一的接口处理不同类型的对象。深入理解继承与多态对于编写高质量的Java程序至关重要。本文将全面介绍Java中继承与多态的概念、实现和应用,帮助您掌握这两个核心特性。
继承基础概念 什么是继承 继承是面向对象编程的核心特性之一,它允许一个类(子类)继承另一个类(父类)的属性和方法。通过继承,子类可以获得父类的特性,同时还可以添加自己的特有功能。
graph TD
A[继承关系] --> B[父类 Parent Class]
A --> C[子类 Child Class]
B --> B1[提供公共属性和方法]
B --> B2[定义通用行为]
B --> B3[被其他类继承]
C --> C1[继承父类特性]
C --> C2[扩展新功能]
C --> C3[重写父类方法]
D[继承的优势] --> D1[代码重用]
D --> D2[建立类层次结构]
D --> D3[实现is-a关系]
D --> D4[支持多态性]
E[继承的特点] --> E1[单继承]
E --> E2[传递性]
E --> E3[不能继承private成员]
继承的语法 Java使用extends
关键字来实现继承:
1 2 3 4 5 6 7 public class 父类名 { } public class 子类名 extends 父类名 { }
动物继承体系示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 public class Animal { protected String name; protected int age; protected String species; public Animal () { this .name = "未知" ; this .age = 0 ; this .species = "未知" ; } public Animal (String name, int age, String species) { this .name = name; this .age = age; this .species = species; } public void eat () { System.out.println(name + " 正在吃东西" ); } public void sleep () { System.out.println(name + " 正在睡觉" ); } public void makeSound () { System.out.println(name + " 发出声音" ); } public void showInfo () { System.out.printf("动物信息 - 姓名:%s,年龄:%d,物种:%s%n" , name, age, species); } 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 String getSpecies () { return species; } public void setSpecies (String species) { this .species = species; } } public class Dog extends Animal { private String breed; public Dog () { super (); this .breed = "未知品种" ; } public Dog (String name, int age, String breed) { super (name, age, "犬科" ); this .breed = breed; } @Override public void makeSound () { System.out.println(name + " 汪汪叫" ); } public void wagTail () { System.out.println(name + " 摇尾巴表示友好" ); } public void guard () { System.out.println(name + " 正在看家护院" ); } @Override public void showInfo () { super .showInfo(); System.out.println("品种:" + breed); } public String getBreed () { return breed; } public void setBreed (String breed) { this .breed = breed; } } public class Cat extends Animal { private boolean isIndoor; public Cat () { super (); this .isIndoor = true ; } public Cat (String name, int age, boolean isIndoor) { super (name, age, "猫科" ); this .isIndoor = isIndoor; } @Override public void makeSound () { System.out.println(name + " 喵喵叫" ); } public void climb () { System.out.println(name + " 正在爬树" ); } public void hunt () { System.out.println(name + " 正在捕猎" ); } @Override public void showInfo () { super .showInfo(); System.out.println("生活环境:" + (isIndoor ? "室内" : "户外" )); } public boolean isIndoor () { return isIndoor; } public void setIndoor (boolean indoor) { isIndoor = indoor; } }
super关键字 super的作用 super
关键字用于访问父类的成员,主要有以下用途:
调用父类的构造方法
访问父类的成员变量
调用父类的成员方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public class Vehicle { protected String brand; protected double price; public Vehicle (String brand, double price) { this .brand = brand; this .price = price; System.out.println("Vehicle构造方法被调用" ); } public void start () { System.out.println("交通工具启动" ); } public void showInfo () { System.out.printf("品牌:%s,价格:%.2f万%n" , brand, price); } } public class Car extends Vehicle { private int doors; private String fuelType; public Car (String brand, double price, int doors, String fuelType) { super (brand, price); this .doors = doors; this .fuelType = fuelType; System.out.println("Car构造方法被调用" ); } @Override public void start () { super .start(); System.out.println("汽车发动机启动" ); } @Override public void showInfo () { super .showInfo(); System.out.printf("车门数:%d,燃料类型:%s%n" , doors, fuelType); } public void honk () { System.out.println(super .brand + " 汽车鸣笛" ); } }
方法重写(Override) 方法重写的概念 方法重写是指子类提供父类方法的新实现。重写的方法必须与父类方法具有相同的方法签名(方法名、参数列表和返回类型)。
方法重写规则 graph TD
A[方法重写规则] --> B[方法签名必须相同]
A --> C[访问权限不能更严格]
A --> D[返回类型相同或为子类型]
A --> E[异常不能更宽泛]
B --> B1[方法名相同]
B --> B2[参数列表相同]
B --> B3[使用@Override注解]
C --> C1[public > protected > default > private]
C --> C2[子类访问权限 >= 父类访问权限]
D --> D1[基本类型必须完全相同]
D --> D2[引用类型可以是子类型]
E --> E1[可以抛出更少的异常]
E --> E2[可以抛出更具体的异常]
F[重写vs重载] --> F1[重写是运行时多态]
F --> F2[重载是编译时多态]
F --> F3[重写在继承关系中]
F --> F4[重载在同一类中]
图形继承体系示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 public abstract class Shape { protected String color; protected double x, y; public Shape (String color, double x, double y) { this .color = color; this .x = x; this .y = y; } public abstract double calculateArea () ; public abstract double calculatePerimeter () ; public void move (double deltaX, double deltaY) { this .x += deltaX; this .y += deltaY; System.out.printf("%s移动到位置(%.1f, %.1f)%n" , getClass().getSimpleName(), x, y); } public void showInfo () { System.out.printf("%s - 颜色:%s,位置:(%.1f, %.1f)%n" , getClass().getSimpleName(), color, x, y); } public String getColor () { return color; } public double getX () { return x; } public double getY () { return y; } } public class Circle extends Shape { private double radius; public Circle (String color, double x, double y, double radius) { super (color, x, y); this .radius = radius; } @Override public double calculateArea () { return Math.PI * radius * radius; } @Override public double calculatePerimeter () { return 2 * Math.PI * radius; } @Override public void showInfo () { super .showInfo(); System.out.printf("半径:%.1f,面积:%.2f,周长:%.2f%n" , radius, calculateArea(), calculatePerimeter()); } public double getRadius () { return radius; } public void setRadius (double radius) { this .radius = radius; } } public class Rectangle extends Shape { protected double width, height; public Rectangle (String color, double x, double y, double width, double height) { super (color, x, y); this .width = width; this .height = height; } @Override public double calculateArea () { return width * height; } @Override public double calculatePerimeter () { return 2 * (width + height); } @Override public void showInfo () { super .showInfo(); System.out.printf("宽度:%.1f,高度:%.1f,面积:%.2f,周长:%.2f%n" , width, height, calculateArea(), calculatePerimeter()); } public double getWidth () { return width; } public void setWidth (double width) { this .width = width; } public double getHeight () { return height; } public void setHeight (double height) { this .height = height; } } public class Square extends Rectangle { public Square (String color, double x, double y, double side) { super (color, x, y, side, side); } @Override public void setWidth (double side) { super .setWidth(side); super .setHeight(side); } @Override public void setHeight (double side) { super .setWidth(side); super .setHeight(side); } public void setSide (double side) { setWidth(side); } public double getSide () { return width; } }
多态性 多态的概念 多态(Polymorphism)是指同一个接口可以有多种不同的实现方式。在Java中,多态主要通过继承和方法重写来实现,允许父类引用指向子类对象。
多态的实现机制 graph TD
A[Java多态机制] --> B[编译时类型检查]
A --> C[运行时动态绑定]
B --> B1[根据引用类型检查]
B --> B2[确保方法存在]
B --> B3[验证访问权限]
C --> C1[根据对象实际类型]
C --> C2[调用对应的重写方法]
C --> C3[实现一个接口多种实现]
D[多态的条件] --> D1[继承关系]
D --> D2[方法重写]
D --> D3[父类引用指向子类对象]
E[多态的优势] --> E1[代码灵活性]
E --> E2[可扩展性]
E --> E3[统一接口处理]
E --> E4[降低耦合度]
多态示例:动物园管理系统 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 public class Zoo { private Animal[] animals; private int count; public Zoo (int capacity) { animals = new Animal [capacity]; count = 0 ; } public void addAnimal (Animal animal) { if (count < animals.length) { animals[count++] = animal; System.out.println("添加动物:" + animal.getName()); } else { System.out.println("动物园已满,无法添加更多动物" ); } } public void makeAllAnimalsSound () { System.out.println("=== 动物园的声音 ===" ); for (int i = 0 ; i < count; i++) { animals[i].makeSound(); } } public void feedAllAnimals () { System.out.println("=== 喂食时间 ===" ); for (int i = 0 ; i < count; i++) { animals[i].eat(); } } public void showAllAnimals () { System.out.println("=== 动物园动物列表 ===" ); for (int i = 0 ; i < count; i++) { animals[i].showInfo(); System.out.println(); } } public void countAnimalTypes () { int dogCount = 0 , catCount = 0 , otherCount = 0 ; for (int i = 0 ; i < count; i++) { if (animals[i] instanceof Dog) { dogCount++; } else if (animals[i] instanceof Cat) { catCount++; } else { otherCount++; } } System.out.println("=== 动物种类统计 ===" ); System.out.println("狗:" + dogCount + "只" ); System.out.println("猫:" + catCount + "只" ); System.out.println("其他:" + otherCount + "只" ); } } public class ZooTest { public static void main (String[] args) { Zoo zoo = new Zoo (10 ); Animal dog1 = new Dog ("小白" , 3 , "金毛" ); Animal dog2 = new Dog ("小黑" , 2 , "拉布拉多" ); Animal cat1 = new Cat ("小花" , 1 , true ); Animal cat2 = new Cat ("小灰" , 4 , false ); zoo.addAnimal(dog1); zoo.addAnimal(dog2); zoo.addAnimal(cat1); zoo.addAnimal(cat2); zoo.makeAllAnimalsSound(); zoo.feedAllAnimals(); zoo.showAllAnimals(); zoo.countAnimalTypes(); } }
向上转型和向下转型 向上转型(Upcasting) 向上转型是指将子类对象赋值给父类引用,这是自动进行的,也是安全的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class CastingDemo { public static void main (String[] args) { Animal animal1 = new Dog ("旺财" , 3 , "柴犬" ); Animal animal2 = new Cat ("咪咪" , 2 , true ); animal1.eat(); animal1.makeSound(); } }
向下转型(Downcasting) 向下转型是指将父类引用转换为子类引用,需要显式转换,并且存在风险。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class DowncastingDemo { public static void main (String[] args) { Animal animal = new Dog ("小明" , 5 , "哈士奇" ); if (animal instanceof Dog) { Dog dog = (Dog) animal; dog.wagTail(); dog.guard(); } try { Cat cat = (Cat) animal; } catch (ClassCastException e) { System.out.println("类型转换失败:" + e.getMessage()); } } }
instanceof运算符 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public class InstanceofDemo { public static void performAnimalAction (Animal animal) { animal.eat(); animal.makeSound(); if (animal instanceof Dog) { Dog dog = (Dog) animal; dog.wagTail(); dog.guard(); } else if (animal instanceof Cat) { Cat cat = (Cat) animal; cat.climb(); cat.hunt(); } System.out.println(animal.getName() + " instanceof Animal: " + (animal instanceof Animal)); System.out.println(animal.getName() + " instanceof Dog: " + (animal instanceof Dog)); System.out.println(animal.getName() + " instanceof Cat: " + (animal instanceof Cat)); } public static void main (String[] args) { Animal dog = new Dog ("汪汪" , 4 , "边牧" ); Animal cat = new Cat ("喵喵" , 3 , false ); performAnimalAction(dog); System.out.println(); performAnimalAction(cat); } }
final关键字 final的用途 final
关键字在继承中有重要作用,它可以用来限制继承和重写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public final class String { } public class FinalMethodDemo { public final void doSomething () { System.out.println("这个方法不能被重写" ); } public void doOtherThing () { System.out.println("这个方法可以被重写" ); } } public class SubClass extends FinalMethodDemo { @Override public void doOtherThing () { System.out.println("重写了父类方法" ); } } public class FinalVariableDemo { private final String CONSTANT = "常量值" ; private static final int MAX_SIZE = 100 ; public void method (final int parameter) { final int localVar = 10 ; } }
继承与多态的最佳实践 设计原则
里氏替换原则 :子类对象应该能够替换父类对象
开闭原则 :对扩展开放,对修改关闭
依赖倒置原则 :依赖抽象而不是具体实现
实际应用:支付系统 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 public abstract class Payment { protected double amount; protected String orderId; public Payment (double amount, String orderId) { this .amount = amount; this .orderId = orderId; } public final boolean processPayment () { if (!validatePayment()) { return false ; } boolean result = executePayment(); if (result) { sendConfirmation(); } return result; } protected abstract boolean executePayment () ; protected boolean validatePayment () { return amount > 0 && orderId != null ; } protected void sendConfirmation () { System.out.println("订单" + orderId + "支付确认已发送" ); } } public class AlipayPayment extends Payment { private String alipayAccount; public AlipayPayment (double amount, String orderId, String alipayAccount) { super (amount, orderId); this .alipayAccount = alipayAccount; } @Override protected boolean executePayment () { System.out.printf("使用支付宝账户%s支付%.2f元,订单号:%s%n" , alipayAccount, amount, orderId); return true ; } @Override protected boolean validatePayment () { return super .validatePayment() && alipayAccount != null ; } } public class WechatPayment extends Payment { private String wechatId; public WechatPayment (double amount, String orderId, String wechatId) { super (amount, orderId); this .wechatId = wechatId; } @Override protected boolean executePayment () { System.out.printf("使用微信账户%s支付%.2f元,订单号:%s%n" , wechatId, amount, orderId); return true ; } } public class BankCardPayment extends Payment { private String cardNumber; private String bankName; public BankCardPayment (double amount, String orderId, String cardNumber, String bankName) { super (amount, orderId); this .cardNumber = cardNumber; this .bankName = bankName; } @Override protected boolean executePayment () { System.out.printf("使用%s银行卡(**** %s)支付%.2f元,订单号:%s%n" , bankName, cardNumber.substring(cardNumber.length()-4 ), amount, orderId); return true ; } } public class PaymentProcessor { public void processPayments (Payment[] payments) { for (Payment payment : payments) { System.out.println("开始处理支付..." ); boolean success = payment.processPayment(); System.out.println("支付结果:" + (success ? "成功" : "失败" )); System.out.println("---" ); } } }
总结 继承与多态是Java面向对象编程的核心特性,本文深入介绍了这两个重要概念:
继承基础 :理解继承的概念、语法和继承关系的建立
super关键字 :掌握访问父类成员的方法
方法重写 :学会正确重写父类方法并遵循重写规则
多态性 :理解多态的实现机制和运行时动态绑定
类型转换 :掌握向上转型和向下转型的使用
final关键字 :了解如何限制继承和重写
最佳实践 :学习在实际项目中合理运用继承与多态
继承提供了代码重用的机制,而多态则为程序设计带来了极大的灵活性。正确理解和运用这两个特性,能够帮助我们设计出更优雅、更易维护的面向对象程序。
参考资料
Oracle Java Documentation - Inheritance
Effective Java by Joshua Bloch
Design Patterns: Elements of Reusable Object-Oriented Software
Java核心技术卷I - 继承与多态