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

day19_抽象类丶接口

由来

当我们声明一个几何图形类:圆、矩形、三角形类等,发现这些类都有共同特征:求面积、求周长、获取图形详细信息。那么这些共同特征应该抽取到一个公共父类中。但是这些方法在父类中又无法给出具体的实现,而是应该交给子类各自具体实现。那么父类在声明这些方法时,就只有方法签名,没有方法体,我们把没有方法体的方法称为抽象方法。Java语法规定,包含抽象方法的类必须是抽象类

抽象类的语法格式

特点:没有方法体且被abstract修饰的方法

抽象方法的语法格式  

特点:抽象方法没有方法体 ,且被abstract关键字修饰

注意事项

关于抽象类的使用,以下为语法上要注意的细节,虽然条目较多,但若理解了抽象的本质,无需死记硬背。

  1. 抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。

    理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。

  2. 抽象类中,也有构造方法,是供子类创建对象时,初始化父类成员变量使用的。

    理解:子类的构造方法中,有默认的super()或手动的super(实参列表),需要访问父类构造方法。

  3. 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。

    理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。

  4. 抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。

    理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。

代码示例

定义抽象类

//抽象类
public abstract class Anima {//类中成员变量private String name;//抽象类中,也有构造方法,是供子类创建对象时,初始化父类成员变量使用的。public Anima(String name) {this.name = name;}public Anima() {}//成员方法public String getName() {return name;}public void setName(String name) {this.name = name;}//抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。public abstract void eat();
}

 定义实现类

public class Dog extends Anima{public Dog(String name) {super(name);}public Dog() {}@Override//抽象类的子类,必须重写抽象父类中所有的抽象方法,除非该子类也是抽象类。 public void eat() {System.out.println("狗狗吃骨头");}
}

定义测试类

public class Test {public static void main(String[] args) {// Anima anima = new Anima();抽象类不能创建对象//只能创建其非抽象子类的对象。Dog dog = new Dog("大黄");dog.eat();//狗狗吃骨头System.out.println(dog.getName());//大黄}
}

接口

由来

电脑边上提供了USB插槽,这个插槽遵循了USB的规范,只要其他设备也是遵循USB规范的,那么就可以互联,并正常通信。至于这个电脑、以及其他设备是哪个厂家制造的,内部是如何实现的,我们都无需关心。

这种设计是将规范和实现分离,这也正是Java接口的好处。Java的软件系统会有很多模块组成,那么各个模块之间也应该采用这种面相接口的低耦合,为系统提供更好的可扩展性和可维护性。

接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要...则必须能...”的思想。继承是一个"是不是"的is-a关系,而接口实现则是 "能不能"的has-a关系。理解:接口是从多个相似类中抽象出来的规范,不需要提供具体实现

  • 例如:你能不能用USB进行连接,或是否具备USB通信功能,就看你是否遵循USB接口规范
  • 例如:Java程序是否能够连接使用某种数据库产品,那么要看该数据库产品有没有实现Java设计的JDBC规范

为什么接口中只能声明公共的静态的常量?

  • 因为接口是标准规范,在规范中需要声明一些底线边界值,当实现者在实现这些规范时,不能去随意修改和触碰这些底线,否则就有“危险”。

接口的定义,它与定义类方式相似,但是使用 interface关键字。它也会被编译成.class文件,但一定要明确接口并不是类,而是另外一种引用数据类型。

接口中可以声明什么?

JDK8之前,接口中只允许出现:

  • 公共的静态的常量:其中public static final可以省略。
  • 公共的抽象的方法:其中public abstract可以省略
//定义接口
public interface Fly {//公共的静态的常量:其中public static final可以省略String name = "示例代码";// 公共的抽象的方法:其中public abstract可以省略void fly();
}

JDK1.8时,接口中允许声明默认方法和静态方法:

  • 公共的默认的方法:其中public 可以省略,建议保留,但是default不能省略。
    • 我们要在已有的老版接口中提供新方法时,如果添加抽象方法,就会涉及到原来使用这些接口的类就会有问题,那么为了保持与旧版本代码的兼容性,只能允许在接口中定义默认方法实现。比如:Java8中对Collection、List、Comparator等接口提供了丰富的默认方法。
    • 当我们接口的某个抽象方法,在很多实现类中的实现代码是一样的,此时将这个抽象方法设计为默认方法更为合适,那么实现类就可以选择重写,也可以选择不重写。
    • 重写时,default单词就不要再写了,它只用于在接口中表示默认方法,到类中就没有默认方法的概念了
  • 公共的静态的方法:其中public 可以省略,建议保留,但是static不能省略。之前的标准类库设计中,有很多Collection/Colletions或者Path/Paths这样成对的接口和类,后面的类中都是静态方法,而这些静态方法都是为前面的接口服务的,那么这样设计一对API,不如把静态方法直接定义到接口中使用和维护更方便
//定义接口
public interface Fly {//默认方法public default void start(){System.out.println("默认方法");}//静态方法public static void show(){System.out.println("静态方法");}
}

JDK1.9时,接口又增加了:

  • 私有方法:因为有了默认方法和静态方法这样具有具体实现的方法,那么就可能出现多个方法由共同的代码可以抽取,而这些共同的代码抽取出来的方法又只希望在接口内部使用,所以就增加了私有方法。

除此之外,接口中不能有其他成员,没有构造器,没有初始化块,因为接口中没有成员变量需要初始化。

接口的声明格式

实现接口

接口的使用,它不能创建对象,但是可以被实现(implements,类似于被继承)。类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类,也习惯称为接口的子类(严格来说,实现类不是子类)。实现的动作类似继承,格式相仿,只是关键字不同,实现使用 implements关键字。

注意:实现类不能继承接口中的静态方法和私有方法

实现接口语法格式

如何调用对应的方法

  • 对于接口的静态方法,直接使用“接口名.”进行调用即可。也只能使用“接口名."进行调用,不能通过实现类的对象进行调用

  • 对于接口的抽象方法、默认方法,只能通过实现类对象才可以调用。接口不能直接创建对象,只能创建实现类的对象

代码示例

定义接口

//定义接口
public interface LiveAble {// 定义抽象方法public abstract void eat();public abstract void breathe();//定义默认方法public default void sleep(){System.out.println("静止不动");}//定义静态方法public static void drink(){System.out.println("喝水");}
}

定义实现类Animal

public class Animal implements LiveAble{//重写/实现接口的抽象方法@Overridepublic void eat() {System.out.println("吃东西");}//重写/实现接口的抽象方法@Overridepublic void breathe(){System.out.println("吸入氧气呼出二氧化碳");}//重写接口的默认方法@Overridepublic void sleep() {System.out.println("闭上眼睛睡觉");}
}

定义实现类Plant

public class Plant implements LiveAble {//重写/实现接口的抽象方法@Overridepublic void eat() {System.out.println("吸收营养");}//重写/实现接口的抽象方法@Overridepublic void breathe(){System.out.println("吸入二氧化碳呼出氧气");}
}

定义测试类

public class Test {public static void main(String[] args) {// 创建实现类(子类)对象Animal a = new Animal();// 调用实现后的方法a.eat(); //吃东西a.sleep(); //闭上眼睛睡觉a.breathe(); //吸入氧气呼出二氧化碳//创建实现类(子类)对象Plant p = new Plant();p.eat(); //吸收营养p.sleep(); //静止不动p.breathe(); //吸入二氧化碳呼出氧气//通过接口调用静态方法LiveAble.drink();// Animal.drink();错误,找不到符号// Plant.drink();错误,找不到符号}
}

接口的多实现

在继承体系中,一个类只能继承一个父类。而对于接口而言,一个类是可以实现多个接口的,这叫做接口的多实现。并且,一个类能继承一个父类,同时实现多个接口。

实现格式:

注意事项:

  • 接口中,有多个抽象方法时,实现类如果不是抽象类就必须重写所有抽象方法。如果抽象方法有重名的,只需要重写一次
  • 当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的抽象方法重名,子类就近选择执行父类的成员方法
  • 当一个类同时实现了多个接口,而多个接口中包含方法签名相同的默认方法时,要么选择保留其中一个,通过“接口名.super.方法名"的方法选择保留哪个接口的默认方法,要么选择自己完全重写

接口的多继承

一个接口能继承另一个或者多个接口接口的继承也使用 extends关键字,子接口继承父接口的方法。最底层的实现类(非抽象类)要实现接口里所有的抽象方法,包括接口继承下来的。

定义接口

package sgg1.demo06;
// 父接口
interface A {void a();public default void methodA(){System.out.println("A类默认方法");}
}
// 父接口
interface B {void b();public default void methodB(){System.out.println("B类默认方法");}
}
//子接口
interface C extends A,B{}
//定义实现类
class D implements C{@Overridepublic void a() { //重写a接口的抽象方法System.out.println("重写a接口的抽象方法");}@Overridepublic void b() {//重写b接口的抽象方法System.out.println("重写b接口的抽象方法");}}

定义测试类

public class Test {public static void main(String[] args) {D d = new D();d.a(); //重写a接口的抽象方法d.b(); //重写b接口的抽象方法d.methodA(); //A类默认方法d.methodA(); //A类默认方法}
}

  接口与实现类对象的多态引用

实现类实现接口,类似于子类继承父类,因此,接口类型的变量与实现类的对象之间,也可以构成多态引用。通过接口类型的变量调用方法,最终执行的是你new的实现类对象实现的方法体。

public class TestInterface {public static void main(String[] args) {Flyable b = new Bird();b.fly(); //展翅高飞Flyable k = new Kite();k.fly(); //别拽我,我要飞}
}
interface Flyable{//抽象方法void fly();
}
class Bird implements Flyable{@Overridepublic void fly() {System.out.println("展翅高飞");}}
class Kite implements Flyable{@Overridepublic void fly() {System.out.println("别拽我,我要飞");}}

http://www.lryc.cn/news/11174.html

相关文章:

  • 【网安神器篇】——系统指纹探测工具finger
  • Prometheus离线tar包安装
  • PostgreSQL查询引擎——SELECT STATEMENTS SelectStmt
  • 零信任-易安联零信任介绍(11)
  • C++ STL——map和set的使用
  • 【Python】thread使用
  • 计网传输层协议:UDP和TCP
  • 一文讲明TCP网络编程、Socket套接字的讲解使用、网络编程案例
  • Java中print和println的区别
  • RocketMq使用规范(纯技术和实战建议)
  • matlab离散系统仿真分析——电机
  • 一文学会进程控制
  • 5.2 BGP水平分割
  • 华为OD机试 - TLV 编码 | 备考思路,刷题要点,答疑 【新解法】
  • 【C语言每日一题】——猜名次
  • Agilent E4982A、Keysight E4982A、LCR 表,1 MHz 至 3 GHz
  • SAP 系统的配置传输
  • 华为OD机试 - 喊七(Python)
  • Docker下快速搭建RabbitMQ单例及集群
  • python代码写开心消消乐
  • 【郭东白架构课 模块一:生存法则】09|法则四:为什么要顺应技术的生命周期?
  • Linux之进程控制
  • SpringBoot社区版专业版带你配置热部署
  • 影响AFE采样精度的因素有哪些?
  • mysqlbackup备份报error:redo log was overwritten
  • Android支持库
  • Vue:filters过滤器
  • Windows环境下安装和配置Gradle
  • 数据结构时间空间复杂度笔记
  • 基于注意力的知识蒸馏Attention Transfer原理与代码解析