原来我一直理解错了:实现接口真的必须实现所有方法吗?

最近在看抽象类的时候,突然发现自己以前有个认知是错的,赶紧记下来分享。

我以前一直以为

实现接口 = 必须把接口里所有方法都实现一遍,少一个都报错。

这个认知对,因为在写SpringBoot项目的时候,项目会分cotroller层,service层,mapper层等,一般我习惯先写控制层,然后调用业务层方法,但是业务层还没有这个方法,我会在业务层的接口补上这个方法,写完时,业务层的实现类就会报红了,因为此时接口多了一个方法,实现类必须实现他,然后我开始去实现类实现这个方法,这一套流程习以为。 但是,最近刷到一个视频,解释接口是什么,有一个操作就是就是使用抽象类实现接口,可以不实现所有方法。 也就是说如果实现接口的是一个抽象类,居然可以只实现部分方法,甚至一个都不实现,编译器都不管你。

java 复制代码
interface Animal {
    void eat();
    void sleep();
    void run();
}

// 抽象类:我就实现一个,咋了?不报错
abstract class Dog implements Animal {
    @Override
    public void eat() {
        System.out.println("吃骨头");
    }
    // sleep和run?我不写,留给子类去写
}

为什么可以这样?

因为抽象类本身就可以有抽象方法,接口里没实现的方法,到了抽象类里自动就变成了抽象方法,继续往下传。相当于"甩锅"给子类。

原来如此我也才恍然大悟,但是更让我意外的是,之前学习的适配器模式,既然用到了这种操作。

假设有一个音频播放器,它只能播放 MP3 文件。现在,我们需要播放 VLC 和 MP4 文件,可以通过创建一个适配器来实现,如下 已有的顶级接口:

java 复制代码
public interface MediaPlayer {
    void play(String audioType, String fileName);
}

已有的高级播放器接口(但不兼容):

java 复制代码
public interface AdvancedMediaPlayer {
    void playVlc(String fileName);
    void playMp4(String fileName);
}

已有的具体播放器类:

java 复制代码
public class VlcPlayer implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file. Name: " + fileName);
    }
    @Override
    public void playMp4(String fileName) {
        // 不支持,但被迫实现
    }
}

public class Mp4Player implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        // 不支持,但被迫实现
    }
    @Override
    public void playMp4(String fileName) {
        System.out.println("Playing mp4 file. Name: " + fileName);
    }
}

AudioPlayer 要实现 MediaPlayer 接口,根据传入格式决定用哪个播放器,这个过程本身没有问题,但是仔细想一想,假如这个高级播放器有十几个方法,那具体的播放器就要被迫去实现这十几个自己根本不支持的方法,这也太不简洁了。

此时此刻,前面说的这种骚操作就派上用场了使用抽象类去实习接口,具体的播放器再去继承这个抽象类,然后有选择性的重写自己需要的方法。

第一步:创建缺省适配器抽象类

java 复制代码
public abstract class AbstractAdvancedMediaPlayer 
        implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        // 默认空实现
    }
    @Override
    public void playMp4(String fileName) {
        // 默认空实现
    }
}

第二步:具体的播放器只重写自己需要的

java 复制代码
public class VlcPlayer extends AbstractAdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file. Name: " + fileName);
    }
    // playMp4 不写,用父类空实现
}

public class Mp4Player extends AbstractAdvancedMediaPlayer {
    @Override
    public void playMp4(String fileName) {
        System.out.println("Playing mp4 file. Name: " + fileName);
    }
    // playVlc 不写,用父类空实现
}

代码瞬间干净了!

总结 这可能是一个很基础的知识,但是平时习惯下你可能并不在意这个细节,可是它在某些地方却起着很大的作用,你不仔细想一想,还真不发现啊。

相关推荐
.痞老板.14 分钟前
java ee--计算机是如何工作的
java·开发语言·java-ee
青梅味猪大肠25 分钟前
【操作系统-60】临近适应算法
java·linux·开发语言·嵌入式硬件·算法·操作系统
CoderYanger26 分钟前
Java EE 进阶:8.MyBatis 操作数据库(入门)(第一弹)
java·数据库·spring·面试·职场和发展·java-ee·mybatis
程序员沉梦听雨29 分钟前
【搜索引擎】Kibana使用指南
java·后端·学习笔记
奶油话梅糖2 小时前
打开项目 0.9 秒、内存只有 IDEA 的 1/12:OpenIDEA 用 Rust 把 IntelliJ IDEA 重造了一遍
java·rust·github·intellij-idea
vipxieliang2 小时前
语言对比卡:PHP vs Go vs Java 的优缺点、适用场景与「为什么选 PHP」
java·go·php
Rain的Java大神之路2 小时前
公交App上“还有2站,约5分钟”怎么实现?90%的人答错这道大厂面试题:GPS漂移、ETA不准、10万QPS热点读全拆透(附完整代码)
java·后端·面试
golang学习记2 小时前
IDEA 2026.3 远程开发迎来重磅升级
java·ide·intellij-idea·远程开发
天天被压力3 小时前
【A股分钟级高频数据完全手册 #04】指数分钟级行情数据接口:沪深指数Pro版最新分时取数
java·人工智能·python
敲代码的小小酥3 小时前
谈SpringMVC与Spring WebFlux的区别与适用场景
java·后端·spring