JAVA抽象类和接口

在Java中,抽象类和接口是实现抽象的两种主要方式。它们都不能被实例化,但可以用来形成类的层次结构,并为子类提供一定程度的框架或模板。

抽象类(Abstract Class)

定义抽象类

抽象类使用abstract关键字定义。它可以包含抽象方法(没有实现的方法)和具体方法(带有实现的方法)。如果一个类包含一个或多个抽象方法,那么这个类必须被声明为抽象的。

abstract class Animal {
    // 抽象方法
    abstract void makeSound();

    // 具体方法
    void eat() {
        System.out.println("This animal eats food.");
    }
}

在上述例子中,Animal类是抽象的,并且它有一个抽象方法makeSound

实现抽象类

要创建一个抽象类的子类,必须提供抽象方法的具体实现。如果子类不实现父类的所有抽象方法,那么子类也必须被声明为抽象的。

class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Bark bark");
    }
}

在这个例子中,Dog类实现了Animal类的makeSound抽象方法。

抽象类的目的
  • 作为其他派生类的基类。
  • 为派生类提供默认行为。
  • 对象的多态性。

接口(Interface)

定义接口

接口是一个完全抽象的类,只包含抽象方法和常量(默认是public static final)。从Java 8开始,接口也可以包含默认方法和静态方法。使用interface关键字定义接口。

interface Animal {
    // 抽象方法
    void makeSound();

    // Java 8 开始允许的默认方法
    default void eat() {
        System.out.println("This animal eats food.");
    }
}

在上述例子中,Animal是一个接口,里面定义了一个抽象方法makeSound和一个默认方法eat

实现接口

类可以通过implements关键字来实现接口。实现接口的类必须提供接口中所有声明的抽象方法的具体实现。

class Dog implements Animal {
    @Override
    public void makeSound() {
        System.out.println("Bark bark");
    }
}

在这个例子中,Dog类实现了Animal接口的makeSound方法。

接口的目的
  • 为类提供一个实现的协议。
  • 支持多继承的行为。
  • 确保派生类遵循特定的形式。
  • 提供一种插件式架构的形式,使得我们可以在运行时添加新功能。

抽象类与接口的主要区别

  • 实例化:抽象类和接口都不能被实例化。
  • 方法定义:抽象类可以包含具体方法,而接口只能包含抽象方法(直到Java 8添加了默认和静态方法)。
  • 构造函数:抽象类可以有构造函数,而接口不能。
  • 状态存储:抽象类可以有实例字段,而接口不能(它们可以有静态常量)。
  • 访问修饰符:抽象类中的方法可以有任何访问修饰符,而接口中的方法默认都是公开的(public)。
  • 继承:一个类只能继承一个抽象类,但可以实现多个接口。

何时使用抽象类和接口

  • 如果要创建一个将由许多紧密相关的对象使用的框架,则应该使用抽象类。
  • 如果要定义非紧密相关的类应实现的功能,或者你需要多继承的行为,应该使用接口。
选择使用抽象类的情况:
  1. 共享代码:如果你想共享代码给几个密切相关的类,你可以将这些代码放在抽象类中。比如,如果多个类有相似的方法实现,那么这些实现可以放在抽象类中作为非抽象方法。

  2. 非公共方法:如果你需要定义非公共访问级别的方法,比如protected方法,那么你需要使用抽象类,因为接口中的所有方法都是公共的。

  3. 状态或字段:如果你的类设计需要有状态,则应该使用抽象类。接口不能保存状态,因为它们不能有实例字段。在抽象类中,你可以有变量和常量,并为这些字段定义状态和行为。

  4. 构造器参数:如果你的类层次结构需要使用构造器参数,抽象类是正确的选择。接口不允许构造器。

选择使用接口的情况:
  1. 多继承:如果你的类需要实现多个不相关类的行为,或者不同类之间需要一个公共协议,那么使用接口。因为Java不支持多重继承,所以使用接口可以绕过这个限制。

  2. 模块化:接口使得你可以创建非常灵活和可扩展的代码。可以在无需修改原有类代码的情况下增加新行为。这种模块化是很多设计模式的核心,如策略模式、工厂模式等。

  3. 解耦:接口有助于解耦,使得实现与接口分离。这样的设计可以让你轻松更换不同的实现,只要它们遵循相同的接口。

Java 8接口的新特性:

从Java 8开始,接口引入了两个新特性:

  1. 默认方法:也称为扩展方法,你可以在接口中提供方法的具体实现,使用default关键字:
public interface Flyable {
    default void fly() {
        System.out.println("Flying");
    }
}
  1. 静态方法:可以在接口中定义静态方法,并且这些方法必须有具体实现:
public interface Flyable {
    static void wingCount(int wings) {
        System.out.println("Wing count: " + wings);
    }
}

默认方法和静态方法增强了接口的功能,允许接口有更多的灵活性和表达力。

总结:

抽象类和接口都有它们各自的使用场景,通常使用抽象类来创建紧密相关的类的通用模板,而接口则为系统提供一组协议,让不相关的类可以实现。接口也支持类似于多继承的功能,可以增加代码的灵活性和可扩展性。随着Java 8和Java 9对接口功能的扩展,接口的使用变得更加灵活,但它们的核心差异依然存在。根据你的设计需求和目标,仔细选择使用抽象类还是接口是非常重要的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员爱学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值