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

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 抽象类

维度 接口 抽象类
关键字 interface abstract 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 表示有限状态。

📖 扩展阅读