10年老兵带你学Java(第5课):接口与抽象类 - 抽象与契约

张开发
2026/4/21 5:36:09 15 分钟阅读

分享文章

10年老兵带你学Java(第5课):接口与抽象类 - 抽象与契约
本课目标抽象类抽象概念的类接口行为的契约两者的区别和使用场景Java 8/9/11 接口新特性上节课学了继承继承是是什么的关系。这节课学接口和抽象类是能做什么的关系。一、抽象类抽象概念的类1.1 什么是抽象类抽象类就是用abstract修饰的类不能直接实例化不能 new。为什么需要抽象类举个例子“动物是一个抽象概念你不能创造一个动物”只能说这是猫或这是狗“形状是一个抽象概念你不能说给我画一个形状”只能说画个圆或画个方抽象类的特点用abstract修饰不能直接new创建对象可以有抽象方法没有方法体的方法也可以有普通方法和属性1.2 抽象类的语法// 抽象类用abstract修饰publicabstractclassAnimal{protectedStringname;// 抽象方法没有方法体子类必须实现publicabstractvoidsound();// 普通方法有方法体子类可以直接继承publicvoideat(){System.out.println(name在吃东西);}// 构造方法子类调用publicAnimal(Stringname){this.namename;}}子类继承抽象类// 用extends继承抽象类publicclassCatextendsAnimal{publicCat(Stringname){super(name);// 调用父类构造}// 必须实现父类的抽象方法Overridepublicvoidsound(){System.out.println(name喵喵喵);}}使用publicclassMain{publicstaticvoidmain(String[]args){// 不能直接new抽象类// Animal a new Animal(); // 错误// 只能创建子类对象AnimalcatnewCat(小花);cat.eat();// 继承来的方法cat.sound();// 重写的方法}}1.3 抽象方法抽象方法是只有方法签名、没有方法体的方法。publicabstractclassAnimal{// 抽象方法没有{}publicabstractvoidsound();publicabstractvoidmove();}子类必须实现所有抽象方法否则子类也必须是抽象类。二、接口行为的契约2.1 什么是接口接口是一种行为规范它定义了一组能做什么的方法但不关心怎么做。打个比方USB接口定义了供电和数据传输的规范不管你是U盘还是鼠标只要符合这个接口就能用Java接口定义了一组方法的规范不管哪个类实现只要符合接口就能互换2.2 接口的语法// 定义接口用interfacepublicinterfaceFlyable{// 接口中的方法默认是抽象的Java 7以前// 抽象方法没有方法体voidfly();// 接口中的属性默认是常量public static finalintMAX_SPEED1000;}类实现接口用 implements// 鸟实现飞接口publicclassBirdimplementsFlyable{Overridepublicvoidfly(){System.out.println(鸟儿扇动翅膀飞翔);}}// 飞机实现飞接口publicclassAirplaneimplementsFlyable{Overridepublicvoidfly(){System.out.println(飞机发动机推动飞翔);}}使用publicclassMain{publicstaticvoidmain(String[]args){// 接口引用指向实现类对象Flyablef1newBird();Flyablef2newAirplane();f1.fly();// 鸟儿扇动翅膀飞翔f2.fly();// 飞机发动机推动飞翔}}2.3 接口的特点接口不能实例化不能new接口的方法默认是抽象的Java 7及以前接口的属性默认是常量public static final一个类可以实现多个接口弥补单继承的不足接口可以继承接口多继承2.4 接口的多实现// 接口1publicinterfaceRunnable{voidrun();}// 接口2publicinterfaceEatable{voideat();}// 一个类可以实现多个接口publicclassPersonimplementsRunnable,Eatable{Overridepublicvoidrun(){System.out.println(人在跑步);}Overridepublicvoideat(){System.out.println(人在吃饭);}}这解决了单继承的问题——类只能继承一个父类但可以实现多个接口。2.5 接口的默认方法Java 8Java 8开始接口可以有默认方法publicinterfaceFlyable{// 抽象方法voidfly();// 默认方法用default修饰有方法体defaultvoidland(){System.out.println(安全降落);}}作用如果接口需要新增方法旧实现类不用全部重写。publicclassBirdimplementsFlyable{Overridepublicvoidfly(){System.out.println(鸟儿飞翔);}// 不需要实现land()可以直接用默认的}// 使用FlyablebnewBird();b.land();// 输出安全降落2.6 接口的静态方法Java 8publicinterfaceMathUtil{staticintmax(inta,intb){returnab?a:b;}}// 调用直接用接口名调用intmMathUtil.max(10,20);// 20三、抽象类 vs 接口3.1 核心区别对比项抽象类接口关键字abstract classinterface继承/实现extends单继承implements多实现属性无限制默认常量public static final方法抽象 普通都可以Java 7抽象方法Java 8抽象 默认 静态构造方法有没有什么时候用是什么的关系能做什么的关系3.2 选择原则用抽象类类之间有明显的是…的关系猫是动物需要共享代码普通方法需要控制属性访问权限用接口类之间有相同的行为但没有继承关系需要多实现一个类实现多个接口需要解耦面向接口编程3.3 经典例子门// 抽象类门抽象概念abstractclassDoor{protectedStringmaterial;publicDoor(Stringmaterial){this.materialmaterial;}// 开门普通方法publicvoidopen(){System.out.println(门打开了);}// 关门普通方法publicvoidclose(){System.out.println(门关上了);}// 报警抽象方法子类实现publicabstractvoidalarm();}// 木门classWoodenDoorextendsDoor{publicWoodenDoor(){super(木头);}Overridepublicvoidalarm(){System.out.println(木头门发出警报哔哔哔);}}// 铁门classIronDoorextendsDoor{publicIronDoor(){super(铁);}Overridepublicvoidalarm(){System.out.println(铁门发出警报滴滴滴);}}四、综合练习宠物店系统4.1 需求用接口和抽象类实现一个宠物店系统抽象类 Pet宠物的基本属性接口 Jumpable能跳的动作接口 Eatable能吃的动作4.2 代码// 抽象类宠物abstractclassPet{protectedStringname;protectedintage;publicPet(Stringname,intage){this.namename;this.ageage;}// 普通方法publicvoidshowInfo(){System.out.println(宠物名name年龄age);}}// 接口能跳interfaceJumpable{voidjump();}// 接口能吃interfaceEatable{voideat();}// 狗继承Pet实现Jumpable和EatableclassDogextendsPetimplementsJumpable,Eatable{publicDog(Stringname,intage){super(name,age);}Overridepublicvoidjump(){System.out.println(name跳起来了);}Overridepublicvoideat(){System.out.println(name在吃狗粮);}}// 猫继承Pet实现Jumpable和EatableclassCatextendsPetimplementsJumpable,Eatable{publicCat(Stringname,intage){super(name,age);}Overridepublicvoidjump(){System.out.println(name轻盈地跳上了桌子);}Overridepublicvoideat(){System.out.println(name在吃猫粮);}}// 主程序publicclassMain{publicstaticvoidmain(String[]args){Pet[]pets{newDog(旺财,3),newCat(小白,2)};System.out.println( 宠物店 );for(Petpet:pets){pet.showInfo();// 强制类型转换后调用接口方法if(petinstanceofJumpable){((Jumpable)pet).jump();}if(petinstanceofEatable){((Eatable)pet).eat();}System.out.println();}// 统一管理能跳的宠物System.out.println( 能跳的宠物 );for(Petpet:pets){if(petinstanceofJumpable){Jumpablej(Jumpable)pet;j.jump();}}}}4.3 运行结果 宠物店 宠物名旺财年龄3 旺财跳起来了 旺财在吃狗粮 宠物名小白年龄2 小白轻盈地跳上了桌子 小白在吃猫粮 能跳的宠物 旺财跳起来了 小白轻盈地跳上了桌子五、常见错误❌ 错误1抽象类能直接newpublicabstractclassAnimal{publicabstractvoidsound();}// 错误抽象类不能实例化AnimalanewAnimal();// 正确AnimalanewCat();❌ 错误2接口属性不是常量publicinterfaceFlyable{// 错误这是常量默认是 public static finalintMAX_SPEED1000;// 如果写intspeed;// 等价于 public static final int speed 1000;}❌ 错误3接口方法漏写publicpublicinterfaceFlyable{// Java 7以前必须写publicvoidfly();// 等价于 public abstract void fly();// 错误子类实现时需要public这里不写会报错voidland();}❌ 错误4抽象方法没有全部实现publicabstractclassAnimal{publicabstractvoidsound();publicabstractvoidmove();}// 错误子类必须实现所有抽象方法classCatextendsAnimal{Overridepublicvoidsound(){System.out.println(喵);}// 缺少move()的实现报错}// 正确classCatextendsAnimal{Overridepublicvoidsound(){System.out.println(喵);}Overridepublicvoidmove(){System.out.println(猫在走);}}六、本课总结抽象类用abstract class定义单继承有构造方法适合是什么的关系可以有抽象方法和普通方法接口用interface定义多实现无构造方法适合能做什么的关系Java 7抽象方法Java 8默认方法、静态方法选择有继承关系用抽象类需要多实现用接口既要继承又要多实现先extends一个类再implements多个接口七、下节课预告第6课常用类String 字符串StringBuilder 可变字符串日期时间 API包装类学完这课你就能更高效地处理数据了。关注我跟着老兵学Java少走弯路。评论区聊聊抽象类和接口哪个更容易搞混

更多文章