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

抽象与接口——Java的“武器模板”与“装备词条”

写 Java 代码时,你有没有过这样的困惑🧐:
明明用普通类也能实现功能,为啥非要搞 “抽象类”“接口” 这些看着 “绕” 的东西?难道就是为了多记几个语法规则?

//基类
class Animal {public void eat() {System.out.println("吃饭,吃的东西不确定...");}public void sleep() {System.out.println("睡觉,姿势不确定...");}
}
//子类Cat,重写方法
class Cat extends Animal {@Overridepublic void eat() {System.out.println("猫吃鱼");}@Overridepublic void sleep() {System.out.println("躺着睡");}
}
//子类Dog,重写方法
class Dog extends Animal {@Overridepublic void eat() {System.out.println("狗吃肉");}@Overridepublic void sleep() {System.out.println("趴着睡");}
}
public class TestOfAnimal {public static void main(String[] args) {Animal a = new Animal();a.eat();a.sleep();System.out.println("-------------");Animal c = new Cat();c.eat();c.sleep();System.out.println("-------------");Animal d = new Dog();d.eat(); d.sleep();}

我又没要求你多精简,我又不是恶魔。 可是,写一个类就复制粘贴这么多东西是什么意思?再这样搞下去,复制粘贴搞的ctrl键也要坏了,最后Java语言真的要被其他语言俘虏了。 作为世界上最好的语言Java的使用者,我可能不得不学习抽象和接口了,真的。

这时我们回答上面那个问题,是为了语法规则?其实不是。你写的普通类,就像游戏里随手捡的 “白板装备”—— 能用来打怪,但遇到复杂场景就歇菜:想让多个类共享部分逻辑,得反复复制粘贴代码🌚;想给不同类加同一功能,又怕改一处牵一发而动全身。

而抽象类和接口,就是解决这些麻烦的 “装备强化系统”:
抽象类帮你把 “多个类的共性逻辑” 打包成 “基础模板”,不用再重复写;接口帮你给类 “按需加功能”,想加多少加多少,还不冲突。


抽象abstract

抽象,简单可理解为不具体、高度概括的,专业描述为:抽象是一种将复杂的概念和现实世界问题简化为更易于理解和处理的表示方法。

在计算机科学和编程中,抽象是一种关注问题的本质和关键特征,而忽略具体实现细节的方法。
在面向对象编程中,抽象是通过定义方法、类和接口来实现的。

抽象方法:将共性的行为(方法)抽取到父类之后,发现该方法的实现逻辑无法在父类中给出具体的实现,就可以将该方法定义为抽象方法。
抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类。

抽象特点

抽象方法和抽象类必须使用 abstract 关键字修饰实现

//抽象方法定义格式
public abstract 返回值类型 方法名(参数列表);
//特别注意:抽象方法只有方法声明,没有方法的实现
//抽象类定义格式
[权限修饰符] abstract class 类名 {0或多个数据成员0或多个构造方法0或多个成员方法
}

抽象类和抽象方法的关系
使用abstract修饰的类就是抽象类
抽象类可以包含,也可以不包含抽象方法
包含抽象方法的类,一定要声明为抽象类

抽象类和普通类区别
抽象类必须使用abstract修饰符
抽象类相对普通类,多了包含抽象方法的能力
抽象类相对普通类,失去了实例化创建对象的能力

抽象类和普通类相同点
符合继承关系特点,能够使用多态机制
子类可以重写从抽象类继承的方法
实例化子类对象需要借助父类构造器实现父类部分的初始化

我们可以举一个真正抽象的例子✌︎' ֊':定义一个形状类Shape,包含抽象方法getArea(),再定义其子类Circle,重写抽象方法,这个例子由于不同形状算面积的不同,比较适合抽象··

// 因为该类中包含了抽象方法,则该类必须声明为抽象类
//定义形状类
abstract class Shape {private String name;public Shape() {System.out.println("Shape()...");}public Shape(String name) {System.out.println("Shape(String)...");this.name = name;}//定义抽象方法,获取形状的面积//因为现在形状不确定,获取面积的功能实现也是不确定的,故而定义为抽象方法public abstract double getArea();
}
//正常子类:必须重写所有抽象方法
class Circle extends Shape {//半径private int r;public Circle() {//super();System.out.println("Circle()...");}//子类构造器需要借助抽象父类构造器,完成父类部分的初始化public Circle(String name, int r) {super(name);System.out.println("Circle(String, int)...");this.r = r;}//重写抽象方法@Overridepublic double getArea() {return 3.14 * r * r;}
}
//抽象类 抽象方法 基础测试
public class Test {public static void main(String[] args) {//1.抽象类不能实例化对象,下面一行编译报错//Shape p = new Shape(); //error//2.抽象类引用可以指向子类(非抽象类)对象Shape p = new Circle("圆",2);//3.实际开发中,主要多态应用double area = p.getArea();System.out.println("area: " + area);}
}

这样我们再来改一改上面的动物案例:

抽象父类Animal:

//该类中包含抽象方法,故而必须声明为抽象类
public abstract class Animal {//抽象类可以包含数据成员private String color;private int age;//抽象类中可以包含抽象方法public Animal() {}public Animal(String color, int age) {this.color = color;this.age = age;}@Overridepublic String toString() {return "Animal [color=" + color + ", age=" + age + "]";}//因为eat和sleep在父类中无法确定其具体功能,故而设置为抽象方法public abstract void eat();public abstract void sleep();
}

正常子类Cat:

public class Cat extends Animal {//温顺度:1-10private int meekValue;public Cat() {}public Cat(String color, int age, int meekValue) {super(color,age);this.meekValue = meekValue;}//子类重写所有的抽象方法@Overridepublic void eat() {System.out.println("猫吃鱼");}@Overridepublic void sleep() {System.out.println("躺着睡");}@Overridepublic String toString() {String msg = super.toString();msg = "Cat: 温顺度=" + this.meekValue + ", " + super.toString();return msg;}
}

抽象子类Dog:

//子类中包含抽象方法,故而必须声明为抽象类
//不可以实例化对象
//public class Dog extends Animal {
public abstract class Dog extends Animal {//忠诚度private int loyalValue;public Dog() {}public Dog(String color, int age, int loyalValue) {super(color,age);this.loyalValue = loyalValue;}//子类重写部分抽象方法@Overridepublic void eat() {System.out.println("狗吃肉");}//子类不重写sleep()抽象方法,则当前类仍旧包含抽象方法
// @Override
// public void sleep() {
// System.out.println("趴着睡");
// }@Overridepublic String toString() {String msg = super.toString();msg = "Dog: 忠诚度=" + this.loyalValue + ", " + 
super.toString();return msg;}
}

Test一下:

public class Test_Animal {public static void main(String[] args) {//1.抽象父类 不可以实例化 对象//Animal a = new Animal(); //编译报错 error//2.抽象父类引用 可以指向 正常子类对象Animal c = new Cat("yellow", 2, 6);c.eat();c.sleep();System.out.println(c);System.out.println("------------");//3.子类如果是抽象类,不可以实例化对象 
// Animal d = new Dog("black", 2, 8); //编译报错
// d.eat();
// d.sleep();
// System.out.println(d);}
}

接口interface

接口是对Java单继承的补充。Java只支持单继承(毕竟亲爹唯一 :-),如果在开发过程中想额外增强类的功能,可以借助接口实现(可以拜师,拜多个师父也不是不可以)。
接口是Java中一种重要的抽象机制,它提供了一种定义行为规范和实现多态性的方式。通过合理使用接口,可以提高代码的可扩展性、可维护性和灵活性。
接口是除了类和数组之外,另外一种引用数据类型,需要使用 interface 关键字来定义,接口最终也会被编译成 .class文件 ,但一定要明确接口并不是类,而是另外一种引用数据类型。

接口基础定义格式:

[修饰符] interface 接口名 {//数据成员,可以定义多个[public static final] 数据类型 数据成员 = 值;//抽象方法:可以定义多个[public abstract] 返回值类型 方法名(形参列表);
}
//使用interface关键字来定义接口
interface IAction {//数据成员,下面2行效果一样//public static final int NUM = 10;int NUM = 10;//成员方法,下面2行效果一样//public abstract void start();void start();public abstract void end();
}
public class Test{public static void main(String[] args) {//接口不可以实例化对象//IAction ac = new IAction(); errorSystem.out.println(IAction.NUM);//接口中数据成员默认 public static final,故而下行编译报错//IAction.NUM = 20;}
}

注意1, 定义类使用关键字 class ,定义接口使用关键字 interface。
注意2,接口中的数据成员,默认 public static final 修饰,是常量,名称一般全大写。
注意3,接口中的方法,默认 public abstract 修饰,是抽象方法。

接口实现

Java中类和类之间的关系是继承,且只能是单继承。
类和接口是实现关系,通过implements关键字表示,可以是单实现,也可以是多实现。
子类还可以在继承一个父类的同时实现多个接口。

接口的实现类书写格式:

//一个类可以同时实现多个接口
[修饰符] class 类名 implements 接口名1,接口名2,... {重写所有抽象方法
}

注意事项:
接口属于引用数据类型的一种,它不是类,它没有构造方法;
接口的实现类(子类),可以是正常类(重写所有抽象方法),也可以是抽象类(包含抽象方法);
接口不能创建对象,一般用接口引用指向实现类对象。

我们可以写一个实现类来实现接口,就刚刚那个←_←:

//定义接口的实现类
class ActionImpl implements IAction {@Overridepublic void start() {System.out.println("start开始执行 ");}@Overridepublic void end() {System.out.println("执行完成,end结束");}
}
public class Test {public static void main(String[] args) {//1.接口不能实例化对象,下面一行编译报错//IAction ic = new IAction();//2.接口引用 指向实现类对象IAction ac = new ActionImpl();//3.接口数据成员访问测试System.out.println(IAction.NUM);System.out.println(ac.NUM);System.out.println("-------------");//4.通过接口引用 调用重写方法(多态体现)ac.start();ac.end();}
}

注意事项: 在类和接口的实现关系中,可以使用多态 ,因为类和接口的实现关系,可理解为继承的一种形式。 一个类可以同时实现多个接口 ,但需要把多个接口的抽象方法全部重写。

接口继承

Java中,类和类之间是单继承关系,接口和接口之间是多继承

接口继承格式:

[修饰符] interface 子接口 extends 父接口1,父接口2... {//新增成员或抽象方法
}

例如:

interface Runable {void run(); 
}
interface Flyable {void fly();
}
//接口多继承
interface Action extends Runable,Flyable {void sing();
}

综合案例

我们定义一个抽象父类Animal2,再定义两个接口IJumpAble跳火圈、IJumpAble骑自行车,最后定义一个猴子类Monkey,去继承Animal2,同时实现IJumpAble、 IJumpAble,进行功能测试。通过这个你可以更好的理解抽象与接口的实用性。

我们先来一个这俩“buff”结合的复杂实现类定义格式:

[修饰符] class 实现类 extends 父类 implements  接口名1, 接口名2, 
... {  重写所有方法; 
}

然后就是案例:

//定义抽象父类
abstract class Animal2 {private String color;private int age;public Animal2() {}public Animal2(String color, int age) {this.color = color;this.age = age;}// 抽象方法public abstract void eat();public abstract void sleep();
}
//定义跳火圈接口
interface IJumpAble {//默认修饰符为:public abstractvoid jump();
}
//定义骑自行车接口 
interface ICycleAble {public abstract void cycle();
}
// 定义猴子类: 继承Animal类,同时实现ICycleAble、IJumpAble接口
class Monkey extends Animal2 implements ICycleAble, IJumpAble 
{private String name;//自定义构造方法public Monkey() {}   public Monkey(String color, int age, String name) {super(color, age);this.name = name;}//重写从父类继承的方法@Overridepublic void eat() {System.out.println("猴子" + name + " 喜欢吃大桃子");}@Overridepublic void sleep() {System.out.println("猴子" + name + " 喜欢在树上睡觉");}// 重写从接口获取的抽象方法@Overridepublic void cycle() {System.out.println("猴子" + name + " 能够骑自行车");}@Overridepublic void jump() {System.out.println(name + " 能够跳火圈");}
}
//测试类
public class Test_Monkey {// 基本测试public static void main(String[] args) {//1.抽象类不能实例化对象,但可以定义引用指向子类对象Animal2 a = new Monkey("yellow", 2, "小悟空");//2.借助抽象类引用,只能访问抽象类中具有的方法a.eat();a.sleep();//下面两行编译报错【多态:编译看左边,运行看右边】//a.jump();//a.cycle();System.out.println("****************");//3.用接口引用指向实现类对象ICycleAble c = new Monkey("yellow", 5, "马戏团小猴");//4.借助接口引用调用接口中重写方法c.cycle();//注意:接口引用类型 只能调用 接口中具备的方法【多态:编译看左边,运行看右边】//下面三行编译报错//c.eat(); error//c.sleep(); error//c.jump(); errorSystem.out.println("****************");//5.如果想要调用父类方法或其他接口方法,可以借助类型转换实现//注意,一定要借助instanceof额外判断引用指向对象的类型if (c instanceof Monkey) {Monkey m = (Monkey) c;m.eat();m.sleep();}System.out.println("****************");if (c instanceof IJumpAble) {IJumpAble j = (IJumpAble) c;j.jump();}}
}

注意事项: 接口多态应用时,编译看左边,运行看右边,即接口引用只能调用接口中包含的方法,成功调用的是重写以后的方法

类接口关系

类与类的关系
继承关系,只能单继承,但是可以多层继承
类与接口的关系
实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
接口与接口的关系
继承关系,可以单继承,也可以多继承

接口特性

1)JDK8新特性:接口可以包含静态方法和默认方法

//JDK8中接口 可以添加默认方法和static方法
interface JDK8Action {// 接口中静态常量String OPS_MODE = "auto";// 接口中抽象方法void start();void stop();//下面是JDK8新特性//默认方法public default void dFun() {System.out.println("in default fun() ...");}//静态方法public static void sFun() {System.out.println("in static fun() ...");}
}
class Demo01 implements JDK8Action {@Overridepublic void start() {System.out.println("重写start() ...");}@Overridepublic void stop() {System.out.println("重写stop() ...");}
}
public class Test_JDK8 {public static void main(String[] args) {//1.接口引用指向实现类对象JDK8Action a = new Demo01();//2.调用实现类重写方法a.start();a.stop();//3.调用default方法a.dFun();//4.JDK8中接口可以定义static方法,但不能通过接口引用调用,只能通过接口名调用//a.sFun(); 编译报错JDK8Action.sFun();}
}

注意事项:JDK8接口可以定义static方法,但不能通过接口引用调用,只能通过接口名调用

2)JDK9新特性:接口可以包含私有方法

//使用interface关键字来定义接口
interface JDK9Action {// 接口中的静态常量String OPS_MODE = "auto";// 接口中的抽象方法void start();//私有方法 jdk9以下报错private void run() {System.out.println("private run() ...");}
}
class Demo02 implements JDK9Action {@Overridepublic void start() {System.out.println("重写start() ...");}
}
//测试类
public class Test_JDK9 {public static void main(String[] args) {//1.接口引用指向实现类对象JDK9Action a = new Demo02();//2.调用实现类重写的抽象方法a.start();//3.调用接口private方法a.run();}
}

接口与抽象类

接口和抽象类有什么区别๛ก(ー̀ωー́ก)?如何选择?

语法结果区别

1. 定义方式:抽象类通过使用 abstract 关键字来定义,而接口使用 interface 关键字来定义
2. 实现方式:一个类可以继承(extends)一个抽象类,而一个类可以实现(implements)多个接口
3. 构造函数:抽象类可以有构造函数,而接口不能有构造函数
4. 方法实现:抽象类可以包含具体的方法实现,而接口只能包含抽象方法,即没有方法体的方法声明
5. 多继承:Java不支持多继承,一个类只能继承一个抽象类,但可以实现多个接口
6. 数据成员:抽象类可以包含普通数据成员和static数据成员,而接口只能包含 static final 修饰的数据成员

设计理念区别

不同的实现类之间体现 like a 的关系 ,接口更加强调行为规范的定义, 适用于多个类具有相同行为规范的情况。 例如:飞机具备飞翔的行为,鸟也具备飞翔的行为,此时我们就可以定义接口包含抽象方法fly(),然后让飞机和鸟分别去实现该接口。飞机 like a 鸟, 因为它们都会fly()飞飞飞~(^_-)。

子类和抽象父类体现的是 is a 的关系 ,抽象类归根到底还是类,它比较特殊,不能被实例化,只能被继承。抽象类用于定义一种通用的模板或者规范,其中可包含了一些具体数据成员、方法实现和抽象方法声明。 例如:前面案例中的形状类Shape,它里面包含方法getArea(),但该方法功能不确定,所以定义成抽象方法,而包含了抽象方法的类Shape也必须被声明为抽象类。定义子类圆形类,其getArea()方法功能是明确的,则子类中重写方法。

结论
如果仅仅是要额外扩展已存在类的功能,则选择定义接口,让类去实现接口;
如果需要创建一组相关的类,且这些类之间有一些共同的行为和属性,那么可以定义一个类作为这些类的父类。如果不想实例化父类对象,则可以把这个父类设置为抽象类。


总结

抽象类与接口是 Java 实现抽象化、解耦与扩展的核心机制,逻辑意义聚焦于解决实际开发痛点:

抽象类用abstract修饰,核心作用是抽取共性、约束子类:通过包含具体方法复用通用逻辑(如 Animal 类的toString()),用抽象方法强制子类实现差异化逻辑(如eat()),同时借助构造器完成子类共性属性初始化,本质是为相关类提供 “统一模板”,避免重复编码,体现 “is a” 的继承逻辑。

接口用interface修饰,核心意义是定义行为规范、支持多能力扩展:JDK8 前通过抽象方法定统一行为(如 IJumpAble 的jump()),JDK8 后默认方法兼容旧实现,静态方法提供工具能力,且类可多实现,突破单继承限制,让类灵活叠加不同能力,体现 “like a” 的行为逻辑,实现跨类行为统一与解耦。


感谢点赞,感觉收藏,感谢关注!如果有错误欢迎大家在评论区及时指出错误,希望这篇文章能帮到你。我是拖码汪,关注我吧,我会持续更新的话*ᴗ͈ˬᴗ͈ෆ

http://www.dtcms.com/a/367280.html

相关文章:

  • 数组本身的深入解析
  • Linux Centos7搭建LDAP服务(解决设置密码生成密文添加到配置文件配置后输入密码验证报错)
  • 记录一下tab梯形圆角的开发解决方案
  • java面试中经常会问到的dubbo问题有哪些(基础版)
  • illustrator-04
  • 观察者模式-红绿灯案例
  • 【LLM】FastMCP v2 :让模型交互更智能
  • Linux下开源邮件系统Postfix+Extmail+Extman环境部署记录
  • 在Anaconda下安装GPU版本的Pytorch的超详细步骤
  • 追觅科技举办2025「敢梦敢为」发布会,发布超30款全场景重磅新品
  • 从“AI炼金术”到“研发加速器”:一个研发团队的趟坑与重生实录
  • B站 XMCVE Pwn入门课程学习笔记(9)
  • 【数学建模学习笔记】机器学习回归:XGBoost回归
  • 本地部署开源数据生成器项目实战指南
  • Agentic AI 架构全解析:到底什么是Agentic AI?它是如何工作的
  • AI助力软件UI概念设计:卓伊凡收到的客户设计图引发的思考
  • 零样本学习与少样本学习
  • QT6(事件与信号及事件过滤器)
  • JavaAI炫技赛:电商系统商品管理模块的创新设计与实践探索
  • 移动端WebView调试 iOS App网络抓包与请求分析工具对比
  • 给文件加密?企业文件加密软件有哪些?
  • 【C语言】第二课 位运算
  • 【正则表达式】 正则表达式匹配位置规则是怎么样的?
  • 【LeetCode数据结构】设计循环队列
  • Python 第三方自定义库开发与使用教程
  • Browser Use 浏览器自动化 Agent:让浏览器自动为你工作
  • AI代码管家:告别烂代码的自动化魔法
  • 数据结构_二叉平衡树
  • 君正交叉编译链工具mips-gcc540-glibc222-64bit-r3.3.0.smaller.bz2编译st-device-sdk-c
  • Stylar AI: 基于AI的平面设计工具