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

Java中抽象类和接口

抽象类和接口

  • 抽象类
    • 抽象类的概念
    • 抽象类的使用
  • 接口
    • 接口的概念
    • 接口的使用
    • 接口使用注意事项
    • 实现多个接口
  • 接口和抽象类的区别

抽象类

抽象类的概念

面向对象语言中所有对象都是用类来描述的,如果在类中没有详细的描述一个具体对象,这就可以被称为抽象类
就像定义了一个Shape图形的类,但是我们并不知道是什么图形,是三角形、还是圆形等等
在这里插入图片描述

这里明显是继承关系,都有一个draw方法,子类重写这个draw方法,父类Shape并不需要具体描述打印那个图形,可以通过子类来确认具体的描述,因此这里的Shape父类就可以被设计成" 抽象类 " 这里的draw方法没有实际的工作,也可以被设计为" 抽象方法 "

抽象类的使用

抽象类如何定义呢?
Java中被 abstract修饰称为抽象类,抽象类中被 abstract修饰的⽅法称为抽象⽅法,抽象⽅法不⽤给出具体的实现体。
例如:

//抽象类
public abstract class Shape{
   public int a = 10;
    //抽象方法
   abstract public void draw();
   abstract void draw1();
   //成员方法
    public void test(){
        
    }
    //构造方法
    public Shape(){
        
    }
}
抽象类也是类可以有抽象方法,也可以有成员变量和成员方法,甚至是构造方法
抽象类中不⼀定包含抽象⽅法,但是有抽象⽅法的类⼀定是抽象类

抽象类的使用注意事项

1.但是这里的抽象类中的抽象方法不可以有具体如何实现
在这里插入图片描述
2.抽象类中的抽象方法不可以被private修饰
在这里插入图片描述
3.抽象类中的抽象方法不可以被final和static所修饰 ,因为这里由于父类的抽象方法不可以具体描述,因此需要借助子类重写来具体实现,但是被final和static所修饰的方法是不可以被重写
在这里插入图片描述
在这里插入图片描述
4.抽象类必须被继承,子类要重写父类中的抽象方法,如果不想要重写要在方法前面加上abstract修饰,让子类中这个方法变成抽象类,但是如果有其他类继承这个子类的话,这个方法还是要被重写

这里如果如果继承了抽象类,不重写抽象类中的抽象方法,编译器会报错
在这里插入图片描述
因此需要重写

abstract class Shape{
    abstract public void draw();
}
class Tra extends Shape{
//重写
    @Override
    public void draw() {
        System.out.println("画一个三角形");
    }
}

如果不想重写那子类就必须被abstract修饰变成抽象类

abstract class Shape{
    abstract public void draw();
}
abstract class Tra extends Shape{

}

5.抽象类无法实例化对象,借助子类对象
在这里插入图片描述
我们以上面的Shape抽象类来举例如何使用

abstract class Shape{
    abstract public void draw();
}
class Tra extends Shape{
    @Override
    public void draw() {
        System.out.println("画一个三角形");
    }
}
class Cycle extends Shape{
    @Override
    public void draw() {
        System.out.println("画一个圆形");
    }
}

public class Test {
    public static void main(String[] args) {
        //抽象类不可以实例化对象
        //需要借助子类
        //向上转型
        Shape shape = new Cycle();
        Shape shape1 = new Tra();
        shape.draw();
        shape1.draw();
    }
}

上面抽象类只能借助继承它的子类进行实例化,不可以直接自己实例化对象,这里也用到了多态的思想,进行实例化和访问

运行结果如下
在这里插入图片描述
我们发现了抽象类和以前的普通类的区别不大,以前普通类也可以继承也可以重写父类的方法,也可以发生多态,那我们为什么要使用abstract抽象类方法
因为就是增加编译器校验,就像在普通类中可以实例化父类对象,但是在抽象类中不可以,所以如果写错,编译器可以帮助我们尽快找到问题

接口

接口的概念

接口其实生活中处处都是,例如:手机充电接口、生活中插板等等
在这里插入图片描述
生活中的插板是可以插好多电器,这些电器必须是符合标准要求

Java中接口可以被看成为多个类的公共规范 ,其他类可以引用这个接口

语法规则
和定义基本类相同,就是把class关键字换成interface关键字就行了

public interface 接⼝名称{
   // 抽象⽅法
} 
//接口定义
public interface Animal{
    public abstract void methodA();//1
    abstract void methodB();//2
    public void methodC();//3
    void methodD();//4
}

上面这4个定义方法是一样的,如果前面不写,编译器会默认为public abstract类型,一般使用第四种,因为这样比较简洁

接口的使用

接口是不可以直接使用的,必须有一个类来实现这个接口,实现接口中的所有抽象方法
接口的使用方法

public  class 类名称 implements 接⼝名称{
   // 接口中抽象类的实现
   //……等其他变量和方法
}

下面有个例子,就是实现一个手机打开和关闭接口收件软件的简单例子

//接口
public interface Phone {
    //打开手机软件
    void openDevice();
    //关闭
    void closeDevice();
}
//音乐软件实现接口
public class Music implements Phone{
    @Override
    public void openDevice() {
        System.out.println("播放音乐");
    }
    public void listenMusic(){
        System.out.println("听音乐");
    }
    @Override
    public void closeDevice() {
        System.out.println("关闭音乐");
    }
}
//拍照软件实现接口
public  class Photo implements Phone{
    @Override
    public void openDevice() {
        System.out.println("打开相机");
    }
    public void takePhoto(){
        System.out.println("拍照片");
    }
    @Override
    public void closeDevice() {
        System.out.println("关闭相机");
    }
}
//使用手机类
public class UsePhone {
    public void open(){
        System.out.println("打开手机-----");
    }
    public void close(){
        System.out.println("关闭手机------");
    }
    //这里的Mushic和Photo都是靠Phone这个接口
    //这里可以实现多态
    public void useDevice(Phone phone){
        //打开相对于软件
        phone.openDevice();
        //判断进入了那个软件,就执行那个软件特有功能
        if(phone instanceof Photo){
            //向下转型
            Photo photo = (Photo) phone;
            //拍照功能
            photo.takePhoto();
        }
        if(phone instanceof Music) {
            Music music = (Music) phone;
            //放音乐功能
            music.listenMusic();
        }
        //关闭软件
        phone.closeDevice();
    }
}
public class Test {
    public static void main(String[] args) {
        //Phone phone = new Phone();
        //接口是一种类型不能直接new新对象
        UsePhone usePhone = new UsePhone();
        //打开手机
        usePhone.open();
        //进入相对于的软件
        usePhone.useDevice(new Music());//音乐
        usePhone.useDevice(new Photo());//拍照
        //关闭手机
        usePhone.close();
    }
}
这里有个Phone接口,和两个子类Music和Photo来实现接口,和一个UsePhone来使用其手机
运用了多态的特征来实现这个手机功能

运行结果如下
在这里插入图片描述

接口使用注意事项

1.接口中方法都是默认是抽象的,因为抽象方法是不可以有主体的,接口中的方法只能由实现接口类实现

如果有主体编译器会报错
在这里插入图片描述
2.接⼝类型是⼀种引⽤类型,但是不能直接实例化接⼝的对象

在这里插入图片描述
但是可以通过子类来实例化对象

interface Phone {
    //打开手机软件
    void openDevice();
    //关闭
    void closeDevice();
}
class Music implements Phone{
    @Override
    public void openDevice() {
        System.out.println("播放音乐");
    }
    public void listenMusic(){
        System.out.println("听音乐");
    }
    @Override
    public void closeDevice() {
        System.out.println("关闭音乐");
    }
}
public class Test {
    public static void main(String[] args) {
        //Phone phone = new Phone();//错误的
        Phone phone = new Music();
        //打开
        phone.openDevice();
        //强制类型转化,向下转型才可以访问
        //子类中特由的方法,和抽象类相同
        Music music = (Music)phone;
        music.listenMusic();
        //关闭
        phone.closeDevice();
    }
}

运行结果如下
在这里插入图片描述
3.接口中的变量会被隐式为public static final 变量

interface Phone {
    //打开手机软件
    int a = 10;
    void openDevice();
    //关闭
    void closeDevice();
}
public class Test {
    public static void main(String[] args) {
        System.out.println(Phone.a);
        //Phone.a= 10;//错误的被final修饰的是不可以修改的
    }
}

静态的变量是通过类名来访问的,这里接口中的a是可以直接使用类名来访问,所以接口中的变量默认是public static final 修饰
运行结果如下
在这里插入图片描述
4.接口中不可以有初始化程序,就像实例代码块、静态代码块和构造方法等等

在这里插入图片描述

实现多个接口

Java虽然不支持多继承(就是一个子类有多个父类),但是支持多个接口

interface Running{
    void run();
}
interface Swimming{
     void swim();
}
//一个Dog类来实现多个接口
class Dog implements Running,Swimming{
   public String name;
   public Dog(String name){
       this.name = name;
   }
    @Override
    public void run() {
        System.out.println(this.name+"跑步");
    }
    @Override
    public void swim() {
        System.out.println(this.name+"游泳");

    }
}
public class Test {

    public static void main(String[] args) {
        Dog dog = new Dog("小七");
        dog.run();
        dog.swim();

    }
}

上面使用Dog类来同时实现Running和Swimming这两个接口,但如果这两个是普通类就不可以多继承
运行结果如下
在这里插入图片描述
既然可以多个接口,那可以继承和实现多个接口一起
例如

//父类
class Animal {
    protected String name;
    public Animal(String name) {
        this.name = name;
    }
}
//接口
interface Fly{
    void fly();
}
interface Running{
    void run();
}
interface Swimming{
    void swim();
}
//继承了Animal类,和一些接口
class Dog extends Animal implements Running,Swimming{
    public Dog(String name){
        super(name);
    }
    @Override
    public void run() {
        System.out.println(this.name+"跑步");
    }
    @Override
    public void swim() {
        System.out.println(this.name+"游泳");
    }
}

这上面就是一个类继承了一个父类,同时实现多个接口
那可以接口继承接口

interface Running{
    void run();
}
interface Swimming{
    void swim();
}
//接口继承接口
interface Animal extends Running,Swimming{
}
//继承了Animal类,和一些接口
class Dog implements Animal{
    public String name;
    public Dog(String name){
        this.name = name;
    }
    @Override
    public void run() {
        System.out.println(this.name+"跑步");
    }
    @Override
    public void swim() {
        System.out.println(this.name+"游泳");
    }
}
public class Test {
    public static void main(String[] args) {
        Animal animal = new Dog("旺财");
        animal.run();
        animal.swim();
    }
}

这里表示一个Animal接口来继承Running和Swimming这两个接口,表示一个动物既可以跑步也可以泳游,如果有类实现Animal接口,就需要把这个Animal接口以及其继承的Running和Swimming接口都要实现,相当于接口之间的合并

运行结果如下
在这里插入图片描述

接口和抽象类的区别

最主要的区别就是 抽象类中可以有普通方法和字段,不是只有抽象方法,而接口中不能包含普通方法和字段(代码块),子类需要重写所有的抽象方法

在这里插入图片描述
到这里就结束了,希望对大家有所帮助,预知后事如何,请听下回分解

相关文章:

  • 详解堆排序(超详细)
  • AI Tokenization
  • Docker 镜像构建与优化
  • 修形还是需要再研究一下
  • Maven中为什么有些依赖不用引入版本号
  • 尝试在软考61天前开始成为软件设计师-数据结构算法
  • 内核编程十:进程的虚拟地址空间
  • Docker Hub Mirror 终极解决方案——0成本,超高速!
  • RAG优化:python从零实现时间管理大师Self-RAG
  • 红宝书第十二讲:详解JavaScript中的工厂模式与原型模式等各种设计模式
  • 第八章:防火墙
  • [实操]Mysql8 InnoDB引擎主从配置三节点操作流程
  • 论文阅读笔记:Denoising Diffusion Implicit Models
  • 消息队列ActiveMQ、RabbitMQ、RocketMQ、Kafka对比分析和选型
  • 【杂谈】Godot4.4 对象池(附脚本)
  • 盖泽 寻边器 帮助类
  • 开发中后端返回下划线数据,要不要统一转驼峰?
  • 【HTML5游戏开发教程】零基础入门合成大西瓜游戏实战 | JS物理引擎+Canvas动画+完整源码详解
  • C# BULK INSERT导入大数据文件数据到SqlServer
  • centos7.9镜像源及Python引入ssl问题处理
  • 金砖国家外长会晤主席声明(摘要)
  • 周劼已任中国航天科技集团有限公司董事、总经理、党组副书记
  • 范宇任上海宝山区副区长
  • 海尔智家一季度营收791亿元:净利润增长15%,海外市场收入增超12%
  • 五大国有银行明确将撤销监事会
  • 美国通过《删除法案》:打击未经同意发布他人私密图像,包括“深度伪造”