欢迎光临
我们一直在努力

京东·Android 面试——接口和抽象类的区别

京东面试到设计环节,常抛一个看似开放的问题:"你写 BaseActivity,用抽象类还是接口?"

很多人脱口而出"抽象类",但说不出所以然。面试官再追问:"那为什么 OnClickListener 是接口不是抽象类?"

空气又安静了。

讲真,接口和抽象类的区别,初级岗背语法,京东要的是你在真实架构里做过取舍。今天从语法、意图、版本演进到实战决策,一次讲透。

一、语法层面的硬差异

面试官:接口和抽象类,语法上到底差哪?

候选人(标准答法):抽象类只能单继承,接口可以多实现;抽象类能有具体方法,接口以前只能有抽象方法。

深度解析:把版本演进放进来才完整。

抽象类(abstract class):

  • 用 abstract 修饰,可含抽象方法(无实现)和具体方法;
  • 可以有普通字段、构造器、非 public 方法;
  • Java 单继承,一个类只能 extends 一个抽象类。

接口(interface):

  • 可以多 implements;
  • Java 8 之前:只能有抽象方法 + public static final 常量;
  • Java 8:加了 default(带实现)和 static 方法;
  • Java 9:又加了 private 方法(给 default 方法拆公共逻辑用)。

abstract class Animal {
protected var legCount = 4 // 能持有状态
abstract fun sound()
fun breathe() = "呼吸" // 具体方法
}
interface Flyable {
fun fly() // 抽象
fun takeOff() { println("起飞") } // Java8 default,带实现
}

普通答法 vs 高分答法:

  • 普通:单继承 vs 多实现,抽象类能有方法体。
  • 高分:我会把"Java 8 的 default、Java 9 的 private"补上,并点出"接口字段只能是 public static final 常量,抽象类字段随便"。这层版本细节,直接拉开和背八股的距离。

二、设计意图:is-a 还是 can-do

本篇第一道核心问答的精髓,不在语法,在语义。

面试官:那什么时候用哪个,凭什么决定?

深度解析:核心区别是关系类型。

  • 抽象类表达"is-a"(是一个):子类是父类的特化。比如 Dog extends Animal,狗"是一个"动物,共享状态(腿数)和行为(呼吸)。抽象类适合做代码复用 + 模板。
  • 接口表达"can-do / 契约"(能做什么):class Bird implements Flyable,鸟"能飞",但飞不是鸟的本质,蜜蜂也能飞。接口定义的是能力,和继承树无关。

这套语义决定了:一个类"是什么"通常只有一个(单继承合理),但"能做什么"可以有很多(多实现合理)。所以 Java 用单继承防歧义,用多接口补灵活。

高分答法:我会举 Android 的例——Activity 本质是 ContextThemeWrapper 的子类(is-a 上下文),所以它用继承;而 View.OnClickListener 是"能响应点击"的能力,任何类都能实现,所以用接口。一句话把语法和语义对上,考官就知道你不是在背。

三、默认方法(default)到底改变了什么

本篇第二道核心问答,是接口演进史上的分水岭。

面试官:Java 8 加了 default method,接口能写实现了,和抽象类还有区别吗?

深度解析:default 的初衷是给老接口无痛加方法。比如 List 在 Java 8 突然要支持 forEach、stream,如果只能加抽象方法,全天下所有 List 实现类都得改,破坏性极大。default 让接口自己提供默认实现,旧实现类零改动就能编译。

interface List<E> {
default void forEach(Consumer<? super E> action) {
for (E e : this) action.accept(e);
}
}

但它带来了新坑——菱形歧义。一个类同时实现两个都有同名 default 的接口,编译器无法二选一,必须你显式重写并用 Interface.super.method() 指定:

interface A { fun foo() = println("A") }
interface B { fun foo() = println("B") }
class C : A, B {
override fun foo() { A.super.foo() } // 必须显式消除歧义
}

普通答法 vs 高分答法:

  • 普通:default 让接口能有方法体,更灵活。
  • 高分:我会强调"default 解决的是接口演进兼容性,不是用来替代抽象类",并点出它重新引入了菱形问题——这是 Java 用单继承规避多年的东西又被 default 撬开了一条缝。理解动机,才算真懂。

四、什么场景必须用抽象类

本篇第三道核心问答,落到"不能让位"的硬约束。

面试官:那有没有场景,只能用抽象类、接口顶不上?

深度解析:有,而且很常见。

1. 需要持有状态(字段):抽象类可以有普通成员变量,接口在 Java 8 之前字段只能是 public static final 常量(全局共享、不可变)。如果你的"基类"要给子类存实例状态,接口做不到。

2. 需要构造器:抽象类能定义构造器,初始化公共状态;接口没有构造器概念。

3. 需要非 public 方法:抽象类能有 protected/private 具体方法做内部复用;接口成员默认 public。

4. 模板方法模式(Template Method):父类定好算法骨架、留钩子给子类填,这是抽象类的经典主场。

Android 实战:

abstract class BaseActivity : AppCompatActivity() {
protected lateinit var binding: ActivityBinding
override fun onCreate(s: Bundle?) { // 模板:固定骨架
super.onCreate(s)
binding = inflateBinding()
setContentView(binding.root)
initView(); initData() // 钩子留给子类
}
abstract fun initView()
abstract fun initData()
}

BaseActivity 必须存 binding 状态、用 protected、走模板方法——这三者接口一个都给不了,所以只能抽象类。而 OnClickListener 只是"能点击",无状态,用接口。

高分答法:我会给个决策口诀——"要状态/构造/模板,选抽象类;要能力/多实现/解耦,选接口"。干脆,不纠结。

五、开放追问:Android 里的现代写法

面试官:Kotlin 里这俩有变化吗?函数式接口又是啥?

深度解析:Kotlin 里抽象类和接口能力更接近了——接口可以有 val/var 属性(虽底层是抽象 getter/setter,仍不能存真正状态字段),可以有默认实现。但"接口不能有构造器、属性背后是方法"这两条铁律没变。

函数式接口(SAM):只有一个抽象方法的接口(如 Runnable、OnClickListener),Kotlin 支持 SAM 转换,用 lambda 替代匿名内部类:

button.setOnClickListener { /* 点击逻辑 */ } // SAM 转换,无需写 object : View.OnClickListener

实战决策树(我常用的):

  • 多个不相关的类都要同一能力 → 接口;
  • 一组类共享代码和状态、有明确父子关系 → 抽象类;
  • 只想当回调/监听器契约 → 函数式接口 + lambda;
  • 既要复用又要多能力 → 抽象类继承 + 多个接口实现(二者组合用)。

高分答法补充:我会提 AndroidX 里的 ListAdapter、DiffUtil 都基于抽象类接收 DiffCallback 接口,正是"抽象类管复用、接口管契约"的组合范式。看源码时注意这种搭配,比死记区别有用。

收尾:几条落地建议

接口和抽象类这道题,京东考的是"你会不会做架构取舍",不是背表。语法是骨架,语义(is-a / can-do)才是灵魂,default 和 SAM 是近现代演进。

面试 Tips(具体答法):

  • 开口先讲语法差异,立刻补 Java 8/9 的 default、private 方法,体现版本跟进。
  • 讲区别必提"is-a vs can-do",并配 Activity/OnClickListener 的 Android 实例。

点赞、在看、转发,三连是对我最大的支持!

「Android 大厂面经·从入门到精通」连载系列

上一篇:第004篇 百度·初级 Android 面试——equals 和 hashCode 的约定

下一篇预告:第006篇 网易·Android 开发面试——匿名内部类为什么要 final

评论区聊聊:你面试遇到过最难的 Android 问题是哪道?

关于本系列:「Android 大厂面经·从入门到精通」是360篇连载系列,覆盖美团、字节跳动、阿里巴巴、快手、百度、京东、华为、小米等30+家公司从 Java 基础到架构师终面的真实面试内容。本篇属于阶段1·入门篇——Java 语言基础。

赞(0)
未经允许不得转载:171主机测评 » 京东·Android 面试——接口和抽象类的区别
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址