Java: 多态与抽象

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

1. 什么是多态

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

(1) 多态的好处

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

2. 向上转型

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

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();  // 编译错误!父类引用只能访问父类的方法
    }
}
▶ 试一试

3. 动态绑定

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

▶ 示例:动态绑定

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());  // 喵喵喵
    }
}
▶ 试一试

4. 抽象类

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

(1) 抽象方法

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

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
    }
}
逻辑代码 50 行(超过 40 行限制,仅展示)

5. 接口

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

(1) 接口定义

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

(2) 接口实现

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();
    }
}
▶ 试一试

6. 接口 vs 抽象类

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

7. 面向接口编程

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表达式。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

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

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