强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Java 完全指南 / 11 - OOP 进阶:继承、多态、抽象类、接口、内部类

11 - OOP 进阶:继承、多态、抽象类、接口、内部类

继承(Inheritance)

// 基类(父类)
public class Animal {
    protected String name;
    protected int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat() {
        System.out.println(name + " 正在吃东西");
    }

    public void sleep() {
        System.out.println(name + " 正在睡觉");
    }

    @Override
    public String toString() {
        return name + ", " + age + "岁";
    }
}

// 子类
public class Dog extends Animal {
    private String breed;  // 品种

    public Dog(String name, int age, String breed) {
        super(name, age);   // 调用父类构造器(必须在第一行)
        this.breed = breed;
    }

    // 子类特有方法
    public void bark() {
        System.out.println(name + " 汪汪叫!");
    }

    // 重写父类方法
    @Override
    public void eat() {
        super.eat();  // 调用父类方法
        System.out.println("  " + name + " 还摇尾巴");
    }

    @Override
    public String toString() {
        return super.toString() + ", 品种: " + breed;
    }
}

public class Cat extends Animal {
    private boolean isIndoor;

    public Cat(String name, int age, boolean isIndoor) {
        super(name, age);
        this.isIndoor = isIndoor;
    }

    public void meow() {
        System.out.println(name + " 喵喵叫!");
    }

    @Override
    public void eat() {
        System.out.println(name + " 优雅地吃猫粮");
    }
}

多态(Polymorphism)

public class PolymorphismDemo {
    // 方法参数使用父类类型 —— 接收任何子类
    static void feedAnimal(Animal animal) {
        System.out.print("喂食: ");
        animal.eat();  // 运行时决定调用哪个子类的 eat()
    }

    public static void main(String[] args) {
        // 向上转型(Upcasting)—— 自动
        Animal dog = new Dog("旺财", 3, "金毛");
        Animal cat = new Cat("咪咪", 2, true);

        // 多态调用
        dog.eat();  // 调用 Dog 的 eat()
        cat.eat();  // 调用 Cat 的 eat()

        // 同一方法,不同行为
        feedAnimal(new Dog("小黑", 2, "拉布拉多"));
        feedAnimal(new Cat("小白", 1, false));

        // 向下转型(Downcasting)—— 需要强制转换
        if (dog instanceof Dog d) {  // JDK 16+ 模式匹配
            d.bark();
        }

        // instanceof 安全检查
        System.out.println("dog 是 Animal: " + (dog instanceof Animal));  // true
        System.out.println("dog 是 Dog: " + (dog instanceof Dog));        // true
        System.out.println("dog 是 Cat: " + (dog instanceof Cat));        // false

        // 数组多态
        Animal[] animals = {
            new Dog("阿黄", 5, "中华田园犬"),
            new Cat("橘猫", 3, true),
            new Dog("哈士奇", 2, "哈士奇")
        };

        for (Animal a : animals) {
            a.eat();
            if (a instanceof Dog d) d.bark();
            if (a instanceof Cat c) c.meow();
            System.out.println("---");
        }
    }
}

抽象类(Abstract Class)

public abstract class Shape {
    protected String color;

    public Shape(String color) {
        this.color = color;
    }

    // 抽象方法 —— 子类必须实现
    public abstract double area();
    public abstract double perimeter();

    // 普通方法 —— 子类可以直接使用
    public String getDescription() {
        return String.format("%s %s: 面积=%.2f, 周长=%.2f",
                           color, getClass().getSimpleName(), area(), perimeter());
    }
}

public class Circle extends Shape {
    private double radius;

    public Circle(String color, double radius) {
        super(color);
        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(String color, double width, double height) {
        super(color);
        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[] shapes = {
            new Circle("红色", 5),
            new Rectangle("蓝色", 4, 6),
            new Circle("绿色", 3)
        };

        double totalArea = 0;
        for (Shape s : shapes) {
            System.out.println(s.getDescription());
            totalArea += s.area();
        }
        System.out.printf("总面积: %.2f%n", totalArea);
    }
}

接口(Interface)

// 接口定义
public interface Drawable {
    void draw();   // 抽象方法(默认 public abstract)
}

public interface Resizable {
    void resize(double factor);
    default double getScale() {    // 默认方法(JDK 8+)
        return 1.0;
    }
    static Resizable of(double scale) {  // 静态方法
        return factor -> scale * factor;
    }
}

public interface Loggable {
    String getLogMessage();
    private void logToFile(String msg) {  // 私有方法(JDK 9+)
        System.out.println("[LOG] " + msg);
    }
    default void log() {
        logToFile(getLogMessage());
    }
}

// 多接口实现
public class GraphicShape implements Drawable, Resizable, Loggable {
    private String name;
    private double scale = 1.0;

    public GraphicShape(String name) {
        this.name = name;
    }

    @Override
    public void draw() {
        System.out.println("绘制 " + name + " (缩放: " + scale + ")");
    }

    @Override
    public void resize(double factor) {
        this.scale *= factor;
        System.out.println(name + " 缩放至 " + scale);
    }

    @Override
    public String getLogMessage() {
        return name + " 已绘制,缩放: " + scale;
    }
}

// 函数式接口(只有一个抽象方法)
@FunctionalInterface
public interface Validator<T> {
    boolean validate(T value);

    // 可以有多个默认方法
    default Validator<T> and(Validator<T> other) {
        return value -> this.validate(value) && other.validate(value);
    }
}

接口 vs 抽象类

维度接口抽象类
关键字interfaceabstract class
多继承✅ 实现多个接口❌ 只能继承一个类
构造器❌ 没有✅ 有
字段只有 public static final可以有各种字段
方法抽象 + 默认 + 静态 + 私有抽象 + 普通方法
设计理念“能做什么”(能力)“是什么”(本质)

Sealed 类(JDK 17+)

// 限制哪些类可以继承
public sealed interface Shape permits Circle, Rectangle, Triangle {}

public record Circle(double radius) implements Shape {}
public record Rectangle(double width, double height) implements Shape {}
public final class Triangle implements Shape {
    private final double a, b, c;
    public Triangle(double a, double b, double c) { this.a = a; this.b = b; this.c = c; }
}
// public class Pentagon implements Shape {} // ❌ 编译错误,未在 permits 列表中

// 配合 switch 模式匹配
public class ShapeCalculator {
    static double area(Shape shape) {
        return switch (shape) {
            case Circle c    -> Math.PI * c.radius() * c.radius();
            case Rectangle r -> r.width() * r.height();
            case Triangle t  -> {
                double s = (t.a() + t.b() + t.c()) / 2;
                yield Math.sqrt(s * (s - t.a()) * (s - t.b()) * (s - t.c()));
            }
        };
        // 不需要 default,编译器知道所有可能的子类型
    }
}

内部类

public class OuterClass {
    private String outerField = "外部字段";

    // 1. 成员内部类
    class MemberInner {
        void show() {
            System.out.println("成员内部类访问: " + outerField);
            System.out.println("外部类引用: " + OuterClass.this);
        }
    }

    // 2. 静态内部类(推荐)
    static class StaticInner {
        void show() {
            System.out.println("静态内部类,不能访问外部实例成员");
        }
    }

    // 3. 局部内部类
    void method() {
        class LocalInner {
            void show() {
                System.out.println("局部内部类访问: " + outerField);
            }
        }
        new LocalInner().show();
    }

    // 4. 匿名内部类
    Runnable task = new Runnable() {
        @Override
        public void run() {
            System.out.println("匿名内部类实现 Runnable");
        }
    };

    public static void main(String[] args) {
        OuterClass outer = new OuterClass();

        // 成员内部类需要外部类实例
        MemberInner mi = outer.new MemberInner();
        mi.show();

        // 静态内部类
        StaticInner si = new StaticInner();
        si.show();

        // 局部内部类
        outer.method();

        // 匿名内部类
        outer.task.run();
    }
}

内部类类型对比

类型定义位置访问外部类使用场景
成员内部类类成员可访问所有成员较少使用
静态内部类类成员(static)只能访问静态成员推荐,如 Map.Entry
局部内部类方法内可访问 effectively final 变量很少使用
匿名内部类表达式中同上一次性使用

枚举实现接口

public enum Operation implements java.io.Serializable {
    ADD("+") {
        @Override
        public double apply(double x, double y) { return x + y; }
    },
    SUBTRACT("-") {
        @Override
        public double apply(double x, double y) { return x - y; }
    },
    MULTIPLY("*") {
        @Override
        public double apply(double x, double y) { return x * y; }
    },
    DIVIDE("/") {
        @Override
        public double apply(double x, double y) { return x / y; }
    };

    private final String symbol;

    Operation(String symbol) { this.symbol = symbol; }
    public String getSymbol() { return symbol; }
    public abstract double apply(double x, double y);

    @Override
    public String toString() {
        return symbol;
    }
}

// 使用
public class EnumInterfaceDemo {
    public static void main(String[] args) {
        for (Operation op : Operation.values()) {
            System.out.printf("10 %s 3 = %.1f%n", op, op.apply(10, 3));
        }
    }
}

⚠️ 注意事项

  1. Java 只支持单继承 — 使用接口实现多重继承的效果。
  2. 优先使用组合而非继承 — 继承破坏封装,组合更灵活。
  3. 重写方法不能降低访问级别public 不能重写为 private
  4. 接口默认方法冲突 — 多接口有同名默认方法时,子类必须显式重写。

💡 技巧

  1. 静态工厂方法替代构造器List.of()Integer.valueOf()
  2. 策略模式 — 使用接口 + Lambda 实现策略选择。
  3. 模板方法模式 — 抽象类定义骨架,子类实现具体步骤。

🏢 业务场景

  • 策略模式: Comparator 接口实现自定义排序。
  • 适配器模式: 内部类实现接口适配。
  • 模板方法: 抽象 AbstractController 定义请求处理流程。
  • 状态模式: Sealed interface + record 表示有限状态。

📖 扩展阅读