Java中抽象类和接口的配合使用

本文介绍了Java中的抽象类和接口的基本概念及使用方法。通过具体示例解释了如何利用抽象类定义通用行为,并通过接口来扩展类的功能。还探讨了接口在回调机制中的应用。
  1. 抽象类
    用abstract定义,用于抽象出一类物品的公共属性和方法,方法可提供默认的实现。如动物类、车类等等。显然意见,抽象类定义的初衷是为了继承。
    子类可以通过extends关键字实现类的继承,与C++不同,Java不能多继承,即:一个类只能有一个父类,所以某些特殊方法就尽量不要放在抽象类中。如动物类(Animal)的捕猎方法(catch)等。
  2. 接口类
    可以认为是一系列方法的集合,类可以通过implements实现接口,在Java中一个类可以实现多个接口。
  3. 典型应用
    我们为门定义一个抽象类Door,并定义抽象方法open和close。现在需定义一个告警门的类AlarmDoor,该门有告警功能(alarm方法)。 AlarmDoor本质上是Door,但同时它也拥有报警的行为功能。此时我们将此应用场合采用如下代码定义,可优雅的实现我们的意图。
abstract class Door
{  
    abstract void open();  
    abstract void close();  
}  

interface Alarm
{  
    void alarm();  
}  

class AlarmDoor extends Door implements Alarm
{  
    void open(){}  
    void close(){}  
    void alarm(){}  
}  
  1. 应用接口实现回调
    假设有下面一个应用场景:有一个农夫,他每天要给牛喂草,牛吃草后产奶给农夫。我们先定义奶牛类Cow,该类中有一个吃草方法(eat),在eat方法中需给农夫增加牛奶(简便起见,吃一个草加一个牛奶)。此时我们在Cow类中定义一个接口,并在类的构造函数中传入接口。然后在eat中调用该接口,实现牛奶的增加。
    农夫类Farmer实现增加牛奶接口(IFMilk),并实现接口的方法addMilk。农夫的喂牛方法Feed中,定义Cow对象,并传入this作为IFMilk接口的实例,成功实现回调。
public class Cow
{
    public Cow(IF_Milk iMilk)
    {
       mIFMilk = iMilk;
    }

    private IF_Milk mIFMilk;
    public interface IF_Milk
    {
        void addMilk(int n);
    }

    public void eat(int nGrass)
    {
        mIFMilk.addMilk(nGrass);
    }
}

public class Farmer implements Cow.IF_Milk
{
    public int myMilk = 0;
    protected void Feed(int nGrass)
    {
        Cow c = new Cow(this);
        c.eat(nGrass);
    }

    public void addMilk(int n)
    {
        myMilk += n;
    }
}
Java 中,**抽象类(Abstract Class)** **接口Interface)** 都是用来实现抽象化的机制,它们都允许我们定义一些未完全实现的行为,从而支持多态、解耦可扩展的设计。但它们的意义、使用场景设计目的有显著区别。 --- ### 一、抽象类的意义 #### 1. **表示“是什么”(is-a 关系)** 抽象类用于描述一对象的共性,强调“继承关系”。它代表一种型,子是它的具体化。 - 例如:`Animal` 是一个抽象类,`Dog` `Cat` 是它的子,表示“狗是一种动物”。 #### 2. **提供部分实现** 抽象类可以包含: - 抽象方法(没有实现,由子实现) - 具体方法(已有实现,子可直接继承或重写) - 成员变量 - 构造器 这使得它可以作为“模板”,封装通用逻辑。 #### 3. **代码复用** 通过抽象类,可以把多个子共有的字段方法提取出来,避免重复编码。 #### 示例代码: ```java abstract class Animal { protected String name; public Animal(String name) { this.name = name; } // 抽象方法:子必须实现 public abstract void makeSound(); // 普通方法:所有子共享 public void sleep() { System.out.println(name + " 正在睡觉"); } } class Dog extends Animal { public Dog(String name) { super(name); } @Override public void makeSound() { System.out.println(name + " 汪汪叫"); } } ``` --- ### 二、接口的意义 #### 1. **表示“能做什么”(has-a capability 或 can-do)** 接口关注的是行为能力,而不是身份。它定义了一组方法契约,任何只要实现该接口,就具备了相应的能力。 - 例如:`Flyable` 接口表示“能飞”,鸟、飞机都可以实现它。 #### 2. **支持多重行为继承** Java 不允许多重继承,但允许一个实现多个接口。 - 例如:一个可以同时实现 `Runnable`、`Serializable`、`Comparable`。 #### 3. **实现松耦合与多态** 接口让程序依赖于抽象而非具体实现,便于替换、测试扩展。 - 例如:`List<String> list = new ArrayList<>();` 程序依赖的是 `List` 接口,而不是具体的 `ArrayList`。 #### 4. **支持函数式编程(Java 8+)** 函数式接口(如 `Predicate<T>`、`Function<T,R>`)配合 Lambda 表达式,使代码更简洁。 #### 示例代码: ```java interface Flyable { void fly(); } interface Swimmable { void swim(); } class Duck implements Flyable, Swimmable { @Override public void fly() { System.out.println("鸭子飞起来了"); } @Override public void swim() { System.out.println("鸭子在游泳"); } } ``` --- ### 三、抽象类 vs 接口的区别总结 | 特性 | 抽象类 | 接口 | |------|--------|-------| | 关键字 | `abstract class` | `interface` | | 方法型 | 可以有抽象方法具体方法 | Java 8 前只能有抽象方法;Java 8+ 支持 `default` `static` 方法 | | 成员变量 | 可以有普通成员变量 | 只能有常量(`public static final`) | | 构造器 | 可以有构造器 | 不能有构造器 | | 继承限制 | 一个只能继承一个抽象类 | 一个可以实现多个接口 | | 设计意图 | “是什么” —— 型继承 | “能做什么” —— 行为契约 | --- ### 四、何时使用抽象类?何时使用接口? | 场景 | 使用建议 | |------|----------| | 多个相关共享代码 | 使用抽象类(代码复用) | | 想要定义对象的型框架 | 使用抽象类 | | 希望具备某种能力(如可比较、可序列化) | 使用接口 | | 需要多重行为组合 | 使用接口 | | 支持 Lambda 表达式 | 使用函数式接口 | | 设计框架时希望用户扩展核心逻辑 | 抽象类(模板方法模式) | | 设计插件化系统或回调机制 | 接口(策略模式、监听器) | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值