当前位置: 首页 > news >正文

Java 抽象类、接口与内部类详解

这是一篇面向初学者的原创学习笔记,适合在学习 Java 面向对象三大特征之后继续深入。本文将系统讲解抽象类、接口、内部类的概念、作用、使用场景以及它们之间的区别,并配合代码示例帮助理解。


一、为什么学这三个知识点?

很多同学学完封装、继承、多态之后,会感觉 Java 面向对象已经差不多了。其实这只是基础部分。接下来最重要的三个知识点,就是:

  • 抽象类
  • 接口
  • 内部类

这三个知识点的共同作用是:让程序结构更清晰、扩展性更强、代码更符合面向对象思想。

简单来说:

  • 抽象类:用于提取“共同特征”,但不适合直接创建对象。
  • 接口:用于定义“规范”或“能力”。
  • 内部类:用于表示“类与类之间更紧密的从属关系”。

如果把它们学明白,后面学习集合、Lambda、设计模式、Spring 框架时会轻松很多。


二、抽象类详解

1. 什么是抽象类?

在现实开发中,有些父类本身只是为了让子类继承,并不是为了直接创建对象。

比如:

  • 动物类Animal
  • 图形类Shape
  • 员工类Employee

这些类更像是一种“模板”或者“规范”,它们描述的是一类事物的共同属性和行为,但具体实现要交给子类完成。

Java 中使用abstract关键字修饰的类,叫做抽象类

abstractclassAnimal{}

2. 抽象类的特点

抽象类有以下几个核心特点:

(1)不能直接创建对象
abstractclassAnimal{}publicclassTest{publicstaticvoidmain(String[]args){// Animal a = new Animal(); // 错误,抽象类不能实例化}}

因为抽象类本身就是“不完整”的类,所以不能直接new

(2)可以有普通方法、成员变量、构造方法

很多初学者误以为抽象类里只能写抽象方法,这是不对的。

abstractclassAnimal{Stringname;publicAnimal(Stringname){this.name=name;}publicvoidsleep(){System.out.println(name+"正在睡觉");}}

说明:

  • 可以有属性
  • 可以有构造器
  • 可以有普通方法
  • 也可以有抽象方法
(3)可以包含抽象方法

抽象方法就是:只有方法声明,没有方法体的方法。

abstractclassAnimal{publicabstractvoideat();}

抽象方法必须放在抽象类中,或者放在接口中。

(4)子类必须重写抽象方法

如果一个类继承了抽象类,那么它必须实现父类中的所有抽象方法,否则这个子类也必须声明为抽象类。

abstractclassAnimal{publicabstractvoideat();}classDogextendsAnimal{@Overridepublicvoideat(){System.out.println("狗啃骨头");}}

3. 抽象类的作用

抽象类最大的作用是:提取共性,强制子类完成某些功能。

比如定义一个动物父类:

abstractclassAnimal{Stringname;publicAnimal(Stringname){this.name=name;}publicvoidsleep(){System.out.println(name+"正在睡觉");}publicabstractvoideat();}classCatextendsAnimal{publicCat(Stringname){super(name);}@Overridepublicvoideat(){System.out.println(name+"正在吃鱼");}}classDogextendsAnimal{publicDog(Stringname){super(name);}@Overridepublicvoideat(){System.out.println(name+"正在啃骨头");}}

测试:

publicclassTest{publicstaticvoidmain(String[]args){Animala1=newCat("小花");Animala2=newDog("大黄");a1.sleep();a1.eat();a2.sleep();a2.eat();}}

输出效果:

小花正在睡觉 小花正在吃鱼 大黄正在睡觉 大黄正在啃骨头

这里就体现了:

  • 父类负责定义公共内容
  • 子类负责实现个性行为
  • 多态让程序更灵活

4. 什么时候用抽象类?

如果多个子类之间有:

  • 相同的属性
  • 相同的普通方法
  • 但某些方法的实现不同

那么就很适合使用抽象类。

比如:

  • 员工类:都要计算工资,但不同岗位计算方式不同
  • 图形类:都要求面积,但不同图形公式不同
  • 支付类:都要支付,但支付方式不同

5. 抽象类的注意事项

(1)抽象类不一定有抽象方法
abstractclassA{publicvoidshow(){System.out.println("hello");}}

这种写法是允许的。

(2)有抽象方法的类一定是抽象类
classA{publicabstractvoidshow();// 错误}
(3)抽象类可以继承抽象类
abstractclassA{publicabstractvoidshow();}abstractclassBextendsA{}
(4)抽象类不能用 final 修饰

因为final表示不能被继承,而抽象类本来就是给子类继承用的,两者冲突。


三、接口详解

1. 什么是接口?

接口可以理解为一种“规则”、“标准”或者“能力说明书”。

比如现实中:

  • USB 接口规定了设备接入方式
  • 充电接口规定了电流、电压、连接方式

在 Java 中,接口也是类似的思想:

它规定某个类“应该具备哪些功能”,但一般不关心这个类内部是怎么实现的。

定义接口使用interface关键字。

interfaceFlyable{voidfly();}

2. 接口的特点

(1)接口不能直接创建对象
interfaceFlyable{voidfly();}publicclassTest{publicstaticvoidmain(String[]args){// Flyable f = new Flyable(); // 错误}}
(2)类实现接口使用 implements
interfaceFlyable{voidfly();}classBirdimplementsFlyable{@Overridepublicvoidfly(){System.out.println("鸟在飞");}}
(3)实现类必须重写接口中的方法

否则这个实现类也要声明为抽象类。

(4)一个类可以实现多个接口

这也是接口非常重要的一个优势。

interfaceFlyable{voidfly();}interfaceSwimmable{voidswim();}classDuckimplementsFlyable,Swimmable{@Overridepublicvoidfly(){System.out.println("鸭子会飞");}@Overridepublicvoidswim(){System.out.println("鸭子会游泳");}}

Java 类只能单继承,但可以多实现接口。


3. 接口中的成员特点

在学习接口时,初学者最容易混乱的就是接口里的成员默认修饰符。

(1)成员变量默认是常量

接口中的变量默认会被public static final修饰。

interfaceA{intNUM=10;}

实际上等价于:

interfaceA{publicstaticfinalintNUM=10;}

因此:

  • 必须赋初值
  • 值不能修改
  • 通常通过接口名.变量名访问
System.out.println(A.NUM);
(2)抽象方法默认是 public abstract
interfaceA{voidshow();}

实际上等价于:

interfaceA{publicabstractvoidshow();}

所以实现类重写时,访问权限不能更小,通常写成:

@Overridepublicvoidshow(){}

4. JDK 8 以后接口的新特性

很多教材只讲老版本接口,但现在开发中还要知道新特性。

(1)默认方法 default

接口中可以有带方法体的方法,但必须用default修饰。

interfaceA{defaultvoidtest(){System.out.println("这是接口中的默认方法");}}

作用:

  • 给接口扩展功能时,不会影响所有实现类
  • 适合添加“默认实现”
(2)静态方法 static
interfaceA{staticvoidshow(){System.out.println("接口中的静态方法");}}

调用方式:

A.show();
(3)私有方法 private

JDK 9 开始,接口中还可以有私有方法,主要用于复用默认方法或静态方法中的重复代码。


5. 接口的作用

接口最核心的作用是:定义规范,降低耦合,增强扩展性。

来看一个例子。

interfaceUSB{voidconnect();voiddisconnect();}classMouseimplementsUSB{@Overridepublicvoidconnect(){System.out.println("鼠标连接成功");}@Overridepublicvoiddisconnect(){System.out.println("鼠标断开成功");}}classKeyboardimplementsUSB{@Overridepublicvoidconnect(){System.out.println("键盘连接成功");}@Overridepublicvoiddisconnect(){System.out.println("键盘断开成功");}}classComputer{publicvoiduseDevice(USBusb){usb.connect();System.out.println("设备正在工作...");usb.disconnect();}}

测试:

publicclassTest{publicstaticvoidmain(String[]args){Computercomputer=newComputer();computer.useDevice(newMouse());computer.useDevice(newKeyboard());}}

这个例子说明:

  • 电脑不需要关心接入的是鼠标还是键盘
  • 只要它们实现了USB接口即可
  • 程序扩展时,只需要新增实现类

这就是接口带来的灵活性。


6. 抽象类和接口的区别

这是面试和学习中非常高频的问题。

对比项抽象类接口
关键字abstract classinterface
是否能实例化不能不能
是否有构造方法没有
是否能有普通方法可以JDK8 之前不可以,之后可以有 default/static 方法
是否能有成员变量可以只能是常量
继承/实现关系单继承可多实现
设计目的提取子类共性定义行为规范

7. 怎么理解两者的使用场景?

你可以这样记:

  • 抽象类表示“是什么”
    • 例如:猫、狗都是动物
  • 接口表示“能做什么”
    • 例如:鸟会飞,鱼会游泳

举例:

abstractclassAnimal{Stringname;publicabstractvoideat();}interfaceFlyable{voidfly();}classBirdextendsAnimalimplementsFlyable{@Overridepublicvoideat(){System.out.println("鸟在吃虫子");}@Overridepublicvoidfly(){System.out.println("鸟在飞翔");}}

这里:

  • Animal表示鸟属于动物这一类
  • Flyable表示鸟具备飞的能力

这个理解方式非常重要。


四、内部类详解

1. 什么是内部类?

如果一个类定义在另一个类的内部,这样的类就叫内部类

classOuter{classInner{}}

内部类本质上也是类,只不过它和外部类的关系更紧密。


2. 为什么要使用内部类?

内部类主要适用于以下场景:

  • 某个类只为另一个类服务,不希望单独暴露出去
  • 内部类需要直接访问外部类的成员
  • 让代码结构更集中、更清晰

也就是说:

如果一个类离不开另一个类,那么就可以考虑把它写成内部类。


五、内部类的分类

Java 中常见的内部类主要有四种:

  1. 成员内部类
  2. 静态内部类
  3. 局部内部类
  4. 匿名内部类

下面分别讲解。


六、成员内部类

1. 定义方式

成员内部类就是定义在外部类的成员位置上的类,和成员变量、成员方法是同一级别。

classOuter{privateStringname="外部类变量";classInner{publicvoidshow(){System.out.println(name);}}}

2. 特点

  • 可以直接访问外部类的所有成员,包括私有成员
  • 创建内部类对象,必须先有外部类对象

3. 创建对象方式

publicclassTest{publicstaticvoidmain(String[]args){Outerouter=newOuter();Outer.Innerinner=outer.newInner();inner.show();}}

注意这个语法:

Outer.Innerinner=outer.newInner();

这是成员内部类最容易考的地方。


七、静态内部类

1. 定义方式

使用static修饰的内部类,叫做静态内部类。

classOuter{staticclassInner{publicvoidshow(){System.out.println("静态内部类方法");}}}

2. 特点

  • 不依赖外部类对象
  • 可以直接创建对象
  • 只能直接访问外部类的静态成员

3. 创建对象方式

publicclassTest{publicstaticvoidmain(String[]args){Outer.Innerinner=newOuter.Inner();inner.show();}}

和成员内部类相比,静态内部类更独立一些。


八、局部内部类

1. 定义方式

局部内部类是定义在方法内部的类。

classOuter{publicvoidmethod(){classInner{publicvoidshow(){System.out.println("局部内部类");}}Innerinner=newInner();inner.show();}}

2. 特点

  • 作用范围只在当前方法中
  • 外部无法直接访问
  • 适合只在某个方法里临时使用的类

这种类在实际开发中不算特别常见,但理解它有助于理解匿名内部类。


九、匿名内部类

1. 什么是匿名内部类?

匿名内部类本质上是:没有名字的局部内部类

它通常用于:

  • 某个类或接口的子类对象只使用一次
  • 为了简化代码书写

例如:

interfaceSwim{voidswim();}publicclassTest{publicstaticvoidmain(String[]args){Swims=newSwim(){@Overridepublicvoidswim(){System.out.println("正在游泳");}};s.swim();}}

这里:

  • new Swim() { ... }就是匿名内部类
  • 它相当于创建了一个实现Swim接口的匿名对象

2. 匿名内部类的使用场景

匿名内部类在以前的 GUI 编程、事件监听、多线程中很常见。

例如创建线程:

publicclassTest{publicstaticvoidmain(String[]args){Threadt=newThread(){@Overridepublicvoidrun(){System.out.println("线程执行中");}};t.start();}}

或者:

Runnabler=newRunnable(){@Overridepublicvoidrun(){System.out.println("任务执行中");}};

当然,Java 8 之后很多这类场景会被 Lambda 表达式替代,但匿名内部类依然要会看、会写。


十、内部类的总结对比

类型定义位置是否依赖外部类对象常见用途
成员内部类类中、方法外表示强依赖关系
静态内部类类中、方法外,带 static工具型、辅助型结构
局部内部类方法内部依赖所在方法环境方法内临时使用
匿名内部类方法内部视场景而定简化一次性对象创建

十一、学习这三个知识点时最容易混淆的地方

1. 抽象类和接口不是一回事

很多初学者会觉得它们都不能创建对象,所以差不多。其实并不是。

  • 抽象类更强调“公共模板”
  • 接口更强调“行为规范”

2. 抽象类可以有构造方法,接口没有

这是一个非常典型的考点。

抽象类虽然不能创建对象,但它的构造器可以给子类初始化父类部分。

3. 成员内部类创建对象必须依赖外部类对象

这个语法必须熟悉:

Outer.Innerinner=outer.newInner();

4. 匿名内部类不是接口,也不是对象名

它本质是“一个没有名字的子类对象”或者“实现类对象”。


十二、实际开发中怎么理解这三个知识点?

如果你想从“应试思维”进入“开发思维”,可以这样理解:

抽象类

适合多个子类共享代码时使用。

比如项目里有很多不同类型的订单处理类,它们都有公共字段和公共方法,这时就可以抽取一个抽象父类。

接口

适合做系统解耦。

比如支付模块中,不同支付方式都实现同一个支付接口。这样以后新增支付宝、微信、银行卡,只需要新增实现类,不用大改原有代码。

内部类

适合让某些类“只在局部生效”或“只服务于某个外部类”。

比如构建者模式中的Builder,经常就会用静态内部类。


十三、一个综合示例帮你彻底理解

下面用一个例子把抽象类、接口、内部类串起来。

abstractclassPerson{protectedStringname;publicPerson(Stringname){this.name=name;}publicabstractvoidwork();}interfaceStudy{voidstudy();}classStudentextendsPersonimplementsStudy{publicStudent(Stringname){super(name);}@Overridepublicvoidwork(){System.out.println(name+"当前的主要任务是学习");}@Overridepublicvoidstudy(){System.out.println(name+"正在认真听课");}staticclassTool{publicvoidshow(){System.out.println("学生使用学习工具");}}}publicclassTest{publicstaticvoidmain(String[]args){Studentstudent=newStudent("小明");student.work();student.study();Student.Tooltool=newStudent.Tool();tool.show();}}

在这个例子中:

  • Person是抽象类,表示“人”的共性
  • Study是接口,表示“学习能力”
  • Student继承抽象类并实现接口
  • Tool是静态内部类,表示学生相关的辅助工具

如果你能理解这个例子,说明这几个知识点已经掌握得比较扎实了。


十四、学习建议

学完这部分后,不要停留在“会背概念”,而要做到下面三点:

1. 自己手写代码

至少把下面例子各写一遍:

  • 抽象类 + 子类重写
  • 接口 + 实现类
  • 成员内部类创建对象
  • 匿名内部类实现接口

2. 自己总结区别

尤其是:

  • 抽象类和接口的区别
  • 成员内部类和静态内部类的区别

3. 带着“为什么”去学

不要只记语法,要理解:

  • 为什么抽象类不能实例化?
  • 为什么接口可以多实现?
  • 为什么成员内部类必须依赖外部类对象?

当你开始思考这些“为什么”的时候,说明你正在真正理解 Java。


十五、结语

抽象类、接口、内部类,是 Java 面向对象中非常关键的进阶内容。

如果说封装、继承、多态是让你“入门面向对象”,那么抽象类、接口、内部类,就是让你开始真正写出更规范、更灵活代码的重要一步。

你可以把它们这样记住:

  • 抽象类:提取共性,定义模板
  • 接口:定义规范,体现能力
  • 内部类:强化关联,局部封装

只要把这三个知识点打牢,后面学集合、多线程、Lambda、Spring 框架时,理解速度会明显提升。


十六、给初学者的练习题

练习 1

定义一个抽象类Shape,包含抽象方法getArea(),再定义CircleRectangle两个子类,分别计算面积。

练习 2

定义一个接口Playable,包含方法play(),让PianoGuitar类实现该接口。

练习 3

定义一个外部类Computer,在里面写一个成员内部类CPU,并在内部类中访问外部类的属性。

练习 4

使用匿名内部类创建一个Runnable对象,并启动线程。


如果你准备把这篇文章发到 CSDN,建议你发布时可以搭配下面这个标题:

Java 抽象类、接口、内部类超详细讲解,看完终于弄懂了

或者:

学完 Java 三大特征后该学什么?抽象类、接口、内部类详解

如果你愿意,我下一步还可以继续帮你做两件事:

  1. 把这篇文章再优化成更像 CSDN 爆款的排版版本
  2. 顺手再给你生成一版配套练习题答案版 md 文档

你要的话我可以继续直接帮你生成。

http://www.jsqmd.com/news/777900/

相关文章:

  • AISMM认证人才缺口达47.8万,2026Q2起头部企业已启动预锁定机制,你的人才梯队准备好了吗?
  • 智能数据采集框架:7个高效策略突破小红书反爬限制
  • 2026年P4高清外墙大屏预算
  • 大模型收藏夹:小白程序员轻松转岗AI赛道,3个月拿高薪Offer的秘诀!
  • Claude Code用户如何配置Taotoken解决密钥与额度困扰
  • 网课小程序怎么制作?教育培训小程序制作流程 - 码云数智
  • 表头与数据列对齐问题解析
  • Armv8-A架构下Cortex-A75系统寄存器详解与开发实践
  • UniApp开发者必读:掌握下拉选择器搜索与重置的终极实现攻略
  • 别再傻傻分不清了!Anaconda和Miniconda到底怎么选?附保姆级安装配置指南
  • 智慧树自动刷课插件:告别手动点击,实现高效学习自动化
  • 2026年上海广告物料制作行业深度横评:源头大厂直供模式如何重塑品质与交付标准 - 优质企业观察收录
  • 告别手动配置!用AD936X Evaluation Software 2.1.3为ZedBoard+AD9361一键生成寄存器脚本
  • 分享WSL2 网络问题解决办法
  • 语音转文字错误多改不完?教你优化转写准确率的方法
  • 2026年普通人如何借助AI翻身?收藏这篇,让你比90%的人早一步抢占先机!
  • 动手调试Linux 0.11:用GDB单步跟踪`switch_to`宏,亲眼看见进程切换的瞬间
  • 2026年武汉英国留学中介通过率高:五家优选深度解析 - 科技焦点
  • 告别GPS信号!用PMW3901光流+VL53L1X激光,在客厅实现无人机‘纹丝不动’悬停
  • ensp实验
  • WinBtrfs:在Windows生态中开辟Linux文件系统疆域的技术桥梁
  • 安科瑞智慧能源管理平台一体化方案,助力传统电力系统向新型电力系统全面转型
  • 西门子6GK5205-3BF00-2AB2工业以太网交换机
  • 机器学习大师课 第 7 课:梯度提升树 ——Kaggle 比赛的 “冠军收割机“
  • 蓝桥杯软件测试模拟赛实战复盘:我是如何用Selenium+Python搞定Web自动化测试的?
  • 2026年贵阳装修公司怎么选?预算透明+环保可信的五大靠谱品牌深度横评指南 - 年度推荐企业名录
  • FPGA IP安全防护与NIST标准实践指南
  • 频谱分析仪核心原理、参数设置与实战避坑指南
  • 歌词滚动姬:免费在线歌词制作工具的终极指南
  • 视频硬字幕AI去除实战指南:基于深度学习的无损修复技术方案