Bootstrap

问:Java中抽象类和接口的差异,真心了解不?

特性抽象类(abstract class)接口(interface)
实例化不能被实例化不能被实例化
定义类型引用可以定义抽象类类型的引用可以定义接口类型的引用
方法实现要求子类需要实现所有抽象方法,否则仍需声明为抽象类实现类需要实现所有方法
构造器可以定义构造器不能定义构造器
方法类型可以包含抽象方法和具体方法只能包含抽象方法(在Java 8及以后可以有默认方法和静态方法)
成员访问修饰符可以是private、默认、protected、public只能是public(包括成员变量和方法)
成员变量可以定义成员变量定义的成员变量实际上是常量(隐式地为public static final)
与抽象方法的关系有抽象方法的类必须被声明为抽象类,但抽象类未必有抽象方法接口中的所有方法默认是抽象方法(Java 8及以后可以有默认实现)
继承/实现使用extends关键字继承使用implements关键字实现
多重继承/实现单继承,但可以实现多个接口一个类可以实现多个接口
用途用于表示一种继承关系,强调”是一种(is-a)"的关系用于表示一种实现关系,强调“具有(has-a)"或者"能做(can-do)"的关系
状态(成员变量)与行为可以包含状态(成员变量)和行为(方法)主要关注行为(方法),不包含状态(成员变量)
设计理念用于对类的抽象,表示一种基类用于定义一组方法的集合,表示一种能力或者契约

简单示例

抽象类
abstract class Animal {
    // 成员变量
    private String name;
    
    // 构造器
    public Animal(String name) {
        this.name = name;
    }
    
    // 抽象方法
    public abstract void makeSound();
    
    // 具体方法
    public void eat() {
        System.out.println(name + " is eating.");
    }
}

class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }
    
    @Override
    public void makeSound() {
        System.out.println("Woof!");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog("Buddy");
        dog.makeSound(); // Woof!
        dog.eat(); // Buddy is eating.
    }
}
接口示例
interface Swimmable {
    // 抽象方法
    void swim();
    
    // Java 8及以后的默认方法
    default void dive() {
        System.out.println("Diving...");
    }
    
    // 静态方法
    static void describeSwimming() {
        System.out.println("Swimming is a form of locomotion.");
    }
}

class Fish implements Swimmable {
    @Override
    public void swim() {
        System.out.println("Fish is swimming.");
    }
}

public class Main {
    public static void main(String[] args) {
        Fish fish = new Fish();
        fish.swim(); // Fish is swimming.
        fish.dive(); // Diving...
        
        Swimmable.describeSwimming(); // Swimming is a form of locomotion.
    }
}

结语

  1. 实例化

    • 抽象类和接口都不能被实例化,但可以通过它们的子类或实现类来创建对象。
  2. 构造器

    • 抽象类可以定义构造器,用于初始化抽象类的成员变量。子类在继承抽象类时,会调用抽象类的构造器。
    • 接口不能定义构造器,因为它不包含任何实例字段。
  3. 方法

    • 抽象类可以包含抽象方法和具体方法。抽象方法必须由子类实现,而具体方法可以直接在抽象类中实现。
    • 接口在Java 8之前只能包含抽象方法。Java 8及以后,接口可以包含默认方法和静态方法。默认方法是非抽象的方法,可以在接口中实现;静态方法是接口级别的方法,不能通过接口实例调用。
  4. 成员访问修饰符

    • 抽象类的成员可以是private、默认、protected、public,这允许抽象类有更多的封装性和灵活性。
    • 接口的成员(包括方法和变量)默认是public的,这意味着它们对所有实现类都是可见的。
  5. 成员变量

    • 抽象类可以定义成员变量,这些变量可以是实例变量或静态变量。
    • 接口中定义的成员变量实际上是常量,它们默认是public static final的,这意味着它们的值在编译时就已经确定,并且不能被修改。
  6. 继承/实现

    • 一个类只能继承一个抽象类(单继承),但可以实现多个接口(多实现)。
    • 这使得接口在需要多重继承的场景中更加有用,因为它允许类实现多个接口来获取不同的能力或契约。
  7. 设计理念

    • 抽象类主要用于类的抽象,表示一种基类或通用类型。它允许子类共享一些通用的实现和状态。
    • 接口主要用于定义方法的集合,表示一种能力或契约。它允许不同的类实现相同的方法集合,从而实现多态性和模块化设计。
;