2202 字
11 min
0

抽象类和接口

在 Java 中,抽象类和接口是实现多态和解耦的核心机制。本文将深入探讨抽象类和接口的定义、区别、使用场景。

抽象类(abstract)

  1. 抽象类用于 提取共性、定义规范,是面向对象编程中非常重要的概念。
  2. 当分析事物时,发现多个类有 共性方法,但具体实现不同,可以把方法声明提取到父类中,而不提供实现,这个方法就称为抽象方法
  3. 抽象方法:只有方法声明,没有方法体,用 abstract 修饰。
  4. 抽象类:包含抽象方法的类,必须用 abstract 修饰。

抽象类的特点

  1. 定义:用 abstract 修饰的类称为抽象类。
  2. 实例化:抽象类不能直接实例化,因为抽象方法只有声明,没有具体实现。
  3. 成员变量:可以定义普通成员变量和静态变量。
  4. 构造方法:抽象类可以有构造方法,方便子类创建对象时初始化抽象类的属性。
  5. 方法类型:可以定义普通方法,也可以定义抽象方法;即使没有抽象方法,也可以是抽象类
  6. 继承关系:抽象类通常作为父类,子类必须重写父类的抽象方法,才能实例化使用。

抽象方法的特点

  1. 定义:用 abstract 修饰的方法称为抽象方法。
  2. 方法体:抽象方法只有声明,没有方法体。
  3. 子类约束:子类必须实现父类的抽象方法,或者子类也声明为抽象类,否则编译失败。
  4. 类限制:抽象方法只能存在于抽象类或接口中,不能存在于普通类中。
  5. 关键字限制abstract 不能与 privatefinalstatic 共存:
    • private:方法不能被继承,也无法重写。
    • final / static:方法可以被继承,但无法重写。
public class Main {
    public static void main(String[] args) {
        // Animal a = new Animal("Animal"); // 编译错误,抽象类不能实例化
        Animal dog = new Dog("Buddy");
        dog.sound(); // 输出: Buddy barks
        dog.eat();   // 输出: Buddy is eating
    }
}
 
abstract class Animal {
    String name;
 
    // 构造方法
    Animal(String name) {
        this.name = name;
    }
 
    // 抽象方法
    abstract void sound();
 
    // 普通方法
    void eat() {
        System.out.println(name + " is eating");
    }
}
 
class Dog extends Animal {
    Dog(String name) {
        super(name);
    }
 
    @Override
    void sound() {
        System.out.println(name + " barks");
    }
}
 

接口(interface)

  1. 接口是完全面向规范的抽象类型,用于定义类必须实现的公共方法规范。
  2. 当一个抽象类中的方法全部是抽象方法时,可以用接口来表示
  3. 抽象类可以包含部分具体方法,而接口不提供任何实现(JDK8+ 支持 default / static 方法除外)。
  4. 接口使用 interface 关键字定义,编译后生成 .class 文件。
  5. 接口不能实例化,实现接口的类必须提供方法具体实现。
  6. 接口支持多继承(使用 extends 实现多个接口的继承)。

接口的组成

  1. 属性:接口中定义的属性都是全局静态常量,默认由 public static final 修饰。

    interface Config {
        int MAX = 100; // 相当于 public static final int MAX = 100;
    }
     
  2. 方法

    • JDK 1.8 之前:接口中只能定义抽象方法,默认 public abstract
    • JDK 1.8+:可以定义 default 方法和静态方法
    • JDK 9+:支持私有方法
    • 接口中不能有构造方法,因为没有实例变量需要初始化
    public class Main {
        public static void main(String[] args) {
            Example obj = new ExampleImpl();
     
            obj.abstractMethod();  // 调用抽象方法的实现
            obj.defaultMethod();   // 调用默认方法(内部会调用私有方法)
            Example.staticMethod(); // 调用静态方法
        }
    }
     
    interface Example {
        void abstractMethod(); // 抽象方法
     
        default void defaultMethod() { // 默认方法
            privateMethod(); // 在接口内部调用私有方法
            System.out.println("default method");
        }
     
        static void staticMethod() { // 静态方法
            System.out.println("static method");
        }
     
        private void privateMethod() { // 私有方法(JDK9+)
            System.out.println("private method");
        }
    }
     
    class ExampleImpl implements Example {
        @Override
        public void abstractMethod() {
            System.out.println("abstract method implemented");
        }
    }
     

接口的实现

  1. 类与接口关系
    • 类与类:继承 → extends
    • 类与接口:实现 → implements
  2. 抽象方法实现
    • 实现接口的类必须重写接口中的抽象方法,完成具体逻辑
    • 如果实现了接口的全部抽象方法 → 类可以实例化
    • 如果只实现部分方法 → 类必须声明为抽象类,不能实例化
  3. 多接口实现
    • 一个类可以实现多个接口,实现多继承效果
    • 避免了类的多重继承带来的复杂性
public class Main {
    public static void main(String[] args) {
        Duck d = new Duck();
        d.fly();   // 输出: Duck is flying
        d.swim();  // 输出: Duck is swimming
        d.land();  // 输出: Landing...
    }
}
 
interface Flyable {
    void fly();           // 抽象方法
    default void land() { // 默认方法
        System.out.println("Landing...");
    }
}
 
interface Swimmable {
    void swim();
}
 
class Duck implements Flyable, Swimmable {
    @Override
    public void fly() {
        System.out.println("Duck is flying");
    }
 
    @Override
    public void swim() {
        System.out.println("Duck is swimming");
    }
}
 

接口和抽象类的区别

接口和抽象类都是面向抽象的设计手段,但侧重点不同:

  1. 接口(interface):对动作或行为的抽象,强调规范和能力。
  2. 抽象类(abstract class):对事物共性或根源的抽象,强调结构和基本特性。

抽象级别(从高到低):

接口 > 抽象类 > 普通类

相同点

  1. 都是向上抽取而来的概念,不能被实例化。
  2. 都可以包含抽象方法,但不提供具体实现。

不同点

  1. 继承关系
    • 抽象类需要被继承(extends),且只能单继承。
    • 接口需要被实现(implements),且可以实现多个接口。
  2. 成员变量
    • 抽象类中可以定义普通成员变量和静态变量。
    • 接口中的变量都是全局静态常量(默认 public static final)。
  3. 构造方法
    • 抽象类可以有构造方法,方便子类初始化属性。
    • 接口不能有构造方法,因为接口没有需要初始化的成员变量。
  4. 方法类型
    • 抽象类可以定义抽象方法和普通方法。
    • 接口(JDK1.8以前)只能定义抽象方法;JDK1.8以后可以定义 default 方法和静态方法;JDK1.9之后支持私有方法。
  5. 语义关系
    • 抽象类描述的是 “is a”,体现体系共性内容。
    • 接口描述的是 “is like a”,体现额外行为或能力。

继承和实现的冲突

当一个类继承父类并实现一个或多个接口时,可能会遇到方法和变量冲突

方法冲突

  1. 方法签名冲突
    • 父类和接口中定义了相同方法签名(名称 + 参数列表),不会产生冲突,子类会直接继承父类的方法实现。
  2. 默认方法冲突
    • JDK8+ 接口可以定义默认方法(default)。
    • 如果父类和接口都有相同签名的方法,父类方法优先。
    • 如果实现了多个接口且接口之间有相同默认方法,子类必须显式重写方法,否则编译器报错。
public class Main {
    public static void main(String[] args) {
        Child c = new Child();
        c.show(); // 输出: Parent show
    }
}
 
interface A {
    default void show() { System.out.println("A show"); }
}
 
interface B {
    default void show() { System.out.println("B show"); }
}
 
class Parent {
    void show() { System.out.println("Parent show"); }
}
 
class Child extends Parent implements A, B {
    @Override
    public void show() {
        super.show(); // 调用父类方法
    }
}
 

变量冲突

  1. 接口间字段冲突

    • 实现多个接口且接口中有同名静态字段时,必须通过接口名指定使用。
    class Z implements X, Y {
        void print() {
            System.out.println(X.VALUE); // 访问 X 接口中的 VALUE
            System.out.println(Y.VALUE); // 访问 Y 接口中的 VALUE
        }
     
        public static void main(String[] args) {
            Z z = new Z();
            z.print();
        }
    }
     
    interface X {
        int VALUE = 1;
    }
     
    interface Y {
        int VALUE = 2;
    }
     
  2. 父类与接口字段冲突

    • 父类和接口有同名字段时,子类需要明确指定使用哪个字段。
    class Child extends Parent implements I {
        void print() {
            System.out.println(super.num); // 访问父类字段
            System.out.println(I.num);     // 访问接口字段
        }
     
        public static void main(String[] args) {
            Child c = new Child();
            c.print();
        }
    }
     
    class Parent {
        int num = 10;
    }
     
    interface I {
        int num = 20;
    }
     

相关文章

评论区