多态与抽象

多态是面向对象的核心特性,让代码更灵活、更易扩展。

什么是多态

多态是指同一个方法在不同对象上有不同的行为。

多态的好处

好处 说明
灵活性 同一接口,不同实现
可扩展性 新增子类不需要修改父类代码
简化代码 用父类引用操作子类对象

向上转型

子类对象可以赋值给父类引用。

JAVA
Animal animal = new Dog();  // 向上转型

示例:向上转型

JAVA
public class Animal {
    public void eat() {
        System.out.println("动物在吃东西");
    }
}

public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗在啃骨头");
    }
    
    public void bark() {
        System.out.println("汪汪叫");
    }
}

public class PolymorphismDemo {
    public static void main(String[] args) {
        Animal animal = new Dog();  // 向上转型
        animal.eat();  // 狗在啃骨头(调用的是Dog的eat)
        // animal.bark();  // 编译错误!父类引用只能访问父类的方法
    }
}
▶ 试一试

动态绑定

运行时根据实际对象类型调用方法,不是编译时类型。

示例:动态绑定

JAVA
public class Animal {
    public void speak() {
        System.out.println("动物发出声音");
    }
}

public class Dog extends Animal {
    @Override
    public void speak() {
        System.out.println("汪汪汪");
    }
}

public class Cat extends Animal {
    @Override
    public void speak() {
        System.out.println("喵喵喵");
    }
}

public class DynamicBinding {
    public static void makeSound(Animal animal) {
        animal.speak();  // 运行时决定调用哪个speak
    }
    
    public static void main(String[] args) {
        makeSound(new Dog());  // 汪汪汪
        makeSound(new Cat());  // 喵喵喵
    }
}
▶ 试一试

抽象类

抽象类不能被实例化,只能被继承。

抽象方法

没有方法体的方法,子类必须实现。

JAVA
public abstract class Shape {
    // 抽象方法:没有方法体
    public abstract double area();
    
    // 普通方法:有方法体
    public void display() {
        System.out.println("面积:" + area());
    }
}

示例:抽象类

JAVA
public abstract class Shape {
    protected String name;
    
    public Shape(String name) {
        this.name = name;
    }
    
    // 抽象方法
    public abstract double area();
    public abstract double perimeter();
    
    public void display() {
        System.out.println(name + " - 面积:" + area() + ",周长:" + perimeter());
    }
}

public class Circle extends Shape {
    private double radius;
    
    public Circle(double radius) {
        super("圆形");
        this.radius = radius;
    }
    
    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
    
    @Override
    public double perimeter() {
        return 2 * Math.PI * radius;
    }
}

public class Rectangle extends Shape {
    private double width, height;
    
    public Rectangle(double width, double height) {
        super("矩形");
        this.width = width;
        this.height = height;
    }
    
    @Override
    public double area() {
        return width * height;
    }
    
    @Override
    public double perimeter() {
        return 2 * (width + height);
    }
}

public class ShapeDemo {
    public static void main(String[] args) {
        Shape circle = new Circle(5);
        Shape rect = new Rectangle(4, 6);
        
        circle.display();  // 圆形 - 面积:78.54,周长:31.42
        rect.display();    // 矩形 - 面积:24.0,周长:20.0
    }
}
▶ 试一试

接口

接口定义了一组规范,实现类必须遵守。

接口定义

JAVA
public interface 接口名 {
    // 常量(默认public static final)
    int MAX_SIZE = 100;
    
    // 抽象方法(默认public abstract)
    void method1();
    int method2(int a);
}

接口实现

JAVA
public class 实现类 implements 接口名 {
    @Override
    public void method1() {
        // 实现
    }
    
    @Override
    public int method2(int a) {
        return a;
    }
}

示例:接口

JAVA
public interface Flyable {
    void fly();
}

public interface Swimmable {
    void swim();
}

public class Duck implements Flyable, Swimmable {
    @Override
    public void fly() {
        System.out.println("鸭子在飞");
    }
    
    @Override
    public void swim() {
        System.out.println("鸭子在游泳");
    }
}

public class InterfaceDemo {
    public static void main(String[] args) {
        Duck duck = new Duck();
        duck.fly();   // 鸭子在飞
        duck.swim();  // 鸭子在游泳
        
        // 接口引用
        Flyable flyer = new Duck();
        flyer.fly();
    }
}
▶ 试一试

接口 vs 抽象类

特性 接口 抽象类
关键字 interface abstract class
实现 implements extends
多实现 支持 不支持
构造方法
成员变量 只能常量 可以有普通变量
方法 抽象方法(Java 8前) 可以有普通方法

面向接口编程

JAVA
public interface Payment {
    void pay(double amount);
}

public class Alipay implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("支付宝支付:" + amount);
    }
}

public class WechatPay implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("微信支付:" + amount);
    }
}

public class PaymentDemo {
    // 面向接口编程
    public static void checkout(Payment payment, double amount) {
        payment.pay(amount);
    }
    
    public static void main(String[] args) {
        checkout(new Alipay(), 100);      // 支付宝支付:100.0
        checkout(new WechatPay(), 200);   // 微信支付:200.0
    }
}

❓ 常见问题

Q 什么时候用抽象类,什么时候用接口?
A 有共同状态和行为用抽象类,只定义规范用接口。
Q 接口可以有方法体吗?
A Java 8之后可以,用default关键字定义默认方法。
Q 向上转型后能调用子类特有方法吗?
A 不能,需要向下转型(强制转换)。

📖 小节

📝 作业

  1. 动物体系: 定义Animal抽象类,Dog、Cat子类,实现多态调用
  2. 图形计算: 定义Shape接口,实现Circle、Rectangle,计算面积
  3. 支付系统: 定义Payment接口,实现多种支付方式

下一课

下一课我们将学习 接口进阶与Lambda,了解接口的高级特性和Lambda表达式。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏