Javaの一篇带你吃透接口

Posted Gremmie102

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Javaの一篇带你吃透接口相关的知识,希望对你有一定的参考价值。

文章目录


1. 🤖 前情提要

随着接口的到来,JavaSE的学习笔记大结局也即将来临,最近的几篇博客写到了封装,继承,多态,抽象类等等,都循序渐进得介绍了这类的知识,大家如果接口这一块理解的很困难的话,建议去完善一下前面的知识哦
👉Java封装
👉静态成员
👉代码块
👉内部类
👉继承
👉多态
👉抽象类

码字不易,本篇博客干货较多,建议收藏食用哦
那么我们就正式进入对接口的介绍

2. 🍚 接口

一图流

2.1 🍟 接口的概念以及一些知识点汇总

接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。
接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法
除非实现接口的类是抽象类,否则该类要定义接口中的所有方法
接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。

2.1.1 🍣 接口与类的相同处

  • 一个接口中可以有多个
  • 接口文件保存在.Java结尾的文件中,文件名使用接口名
  • 接口的字节码文件保存在.class结尾的文件中
  • 接口相应的字节码文件必须在与包名称相匹配的目录结构中

2.1.2 🍜 接口与类的不同处

  • 接口不能用于实例化对象
  • 接口没有构造方法
  • 接口中所有的方法必须是抽象方法,在Java8之后接口中可以使用default关键字修饰的非抽象方法
  • 接口不能包含成员变量,除了static和final变量
  • 接口被类继承这个概念不准确,准确来说应该是要被类实现
  • 接口可以实现我们所说的多继承

2.1.3 🍔 接口的一些特点

  • 接口中每一个方法也是隐式抽象的,所以接口中的方法会被隐式得指定为public abstract (只可以是public abstract,其他修饰符都会报错)
  • 接口中含有变量,但是接口中得变量会被隐式的指定为public static final 变量(并且只能是public,用private修饰会报编译错误)
  • 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法

2.1.4 🍛 抽象类和接口的区别

在JDK1.8以前,它们有如下区别👇

  • 抽象类中的方法可以有具体可执行的语句,即方法体,就是能实现方法的具体功能,但是接口中的方法就不行(比如:System.out.println(“I’m super corn!!”);
  • 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的
  • 接口中不能含有静态代码块以及静态方法的使用(用static修饰的方法),而抽象类可以有静态代码块和静态方法
  • 一个类只能继承一个抽象类,而一个类却可以实现多个接口

那么这里要注意的是:
JDK1.8以后,接口中允许含有静态方法和方法体,允许包含具体实现的方法,该方法我们称之为“默认方法”,这种方法使用default关键字来修饰
JDK1.9以后,允许将方法定义为private,使某些复用的代码不会将方法暴露出去
抽象类存在的意义是为了让编译器更好地校验,一般抽象类我们不会直接使用,而是使用它的子类,如果不小心通过抽象类创建了对象,编译器就会及时提醒我们。

注意🍙:以上内容大致浏览一遍即可,看不懂没关系,下面我将为你一一讲解,然后回头再来看这些知识点将会有一种大梦初醒的感觉


那么在现实生活中,接口是什么呢?它可以是笔记本上的USB口,电源插座等


那么这些接口在实现意义上以及使用标准上也有所不同

  • 电脑的USB口上,可以插:U盘、鼠标、键盘…所有符合USB协议的设备
  • 电源插座插孔上,可以插:电脑、电视机、电饭煲…所有符合规范的设备

通过上述的例子我们就可以看出:接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型

2.2 🍱 语法规则

接口的定义格式与定义类的格式基本上相同,将class关键字换成interface关键字就定义了一个接口。

public interface 接口名称
    //抽象方法
    public abstract void method1();
    //public abstract是固定搭配,可以不写
    public void method2();
    abstract void method3();
    void method4();
    
    //注意:在接口中上述的写法都是抽象方法,所以method4这样写代码更整洁

提示🍙 :

  1. 创建接口时,接口的命名一般以大写字母I(读ai)开头
  2. 接口的命名一般使用形容词词性的单词
  3. 阿里编码规范中约定,接口中的方法和属性不要加任何修饰符,保持代码的整洁性

2.3 🍕 接口的使用

接口不能直接实例化使用,必须要有一个类去实现它,实现接口中所有的抽象方法

public class 类名称 implements 接口名称
    //...

注意🍙 :子类和父类之间是extends继承关系,类与接口之间是implements实现关系。

笔记本电脑中使用USB鼠标,USB键盘的类和接口实现功能

  1. USB接口:包含打开设备、关闭设备的功能
  2. 笔记本类:包含开关机功能、使用USB设备功能
  3. 鼠标类:实现USB接口,并具备点击功能
  4. 键盘类:实现USB接口,并具备输入功能
//USB接口
public interface USB
    void openDevice();
    void closeDevice();


//鼠标类,实现USB接口
public class Mouse implements USB
    @Override
    public void openDevice()
        System.out.println("打开鼠标");
    
    
    @Override
    public void closeDevice()
        System.out.println("关闭鼠标");
    
    public void click()
        System.out.println("鼠标点击");
    


//键盘类,实现USB接口
public class KeyBoard implements USB 
    @Override
    public void openDevice()
        System.out.println("打开键盘");
    
    
    @Override
    public void closeDevice()
        System.out.println("关闭键盘");
    
    
    public void inPut()
        System.out.println("键盘输入");
    


//笔记本类:使用USB设备
public class Computer 
    public void powerOn()
        System.out.println("打开笔记本电脑");
    
    
    public void powerOff()
        System.out.println("关闭笔记本电脑");
    
    public void useDevice(USB usb)
        usb.openDevice();
        if(usb instanceof Mouse)
            Mouse mouse = (Mouse)usb;
            mouse.click();
        else if(usb instanceof KeyBoard)
            KeyBoard keyBoard = (KeyBoard)usb;
            keyBoard.inPut();
        
        usb.closeDevice();
    


//测试类:
public class TestUSB
    public static void main(String[] args)
        Computer computer = new Computer();
        computer.powerOn();
   
    //使用鼠标设备
    computer.useDevice(new Mouse());
    
    //使用键盘设备
    computer.useDevice(new KeyBoard());
    
    computer.powerOff();
    

输出:👇

2.3.1 👻 instanceof

上面的代码示例中,提到了instanceof,可能有小伙伴不太理解,我在前面的博客中有介绍,这里再重新为大家讲解一下
instanceof是Java的一个保留关键字,左边为对象,右边为类,返回类型是Boolean类型。
它的具体作用是测试左边的对象是否是右边类或者右边类的子类创建的实例化对象
如果是,则返回true,否则返回false
【instanceof使用注意事项】
现有继承关系,再有instanceof的使用(包括接口的实现)

【instanceof应用场景】
需要用到对象的强制类型转换时,需要使用instanceof进行判断

2.4 🌭接口的特性

  1. 接口类型是一种引用类型,但是不能直接new接口的对象
public class TestUSB 
    public static void main(String[] args)
        USB usb = new USB();
    


//编译会出错:USB是抽象的,无法实例化

  1. 接口中每一个方法都是public的抽象方法,即接口中的方法会被隐式地指定为public abstract(只能是public abstract,其他修饰符都会报错)
public interface USB 
    //编译出错:此处不允许使用修饰符private
    //或者是java: 缺少方法主体, 或声明抽象
    private void openDevice();
    void closeDevice();
    //不同JDK版本编译器的标准是不一样的,报错也是不一样的

  1. 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现
public interface USB 
    void openDevice();
    
    //编译失败:因为接口中的方法默认为抽象方法
    //Error:接口抽象方法不能带有主体


但这里如果我们加上一个default,那么就可以实现方法体了。

  1. 重写接口中的方法时,不能使用default作为访问权限修饰
public interface USB 
void openDevice();//默认为public
void closeDevice();//默认为public

public class Mouse implements USB 
    @Override
    void openDevice()
        System.out.println("打开鼠标");
    
    
    //...

//这里编译会报错,重写USB中的openDevice方法时,不能使用默认修饰符


实现这个接口,重写这个接口的方法的访问限定修饰符范围要比接口中的更大

  1. 接口中可以含有变量,但是接口中的变量会被编译器自动隐式指定为public static final变量
public interface USB 
    double brand = 3.0;//默认为:final public static修饰
    void openDevice();
    void closeDevice();


public class TestUSB 
    public static void main(String[] args)
        System.out.println(USB.brand);
        //可以直接通过接口名访问,说明变量时静态的
        
        //下面写法会报错 Java:无法为最终变量brand分配值
        USB.brand = 2.0;
        //说明brand具有final属性
    

  1. 接口中不能有静态代码块和构造方法
public interface USB 
    public USB()
    
    //编译失败
    
    
    
    //编译失败
    
    void openDevice();
    void closeDevice();

  1. 接口虽然不是类,但是接口编译完成之后的字节码文件的后缀格式也是.class
  2. 如果类没有实现接口中的所有抽象方法,则类必须设置为抽象类
  3. JDK8中规定了接口中可以包含上面所说的default方法

2.5 🍤 实现多个接口

在Java中,类和类之间是单继承的,一个类只能由一个父类,即Java中不支持多继承,但是一个类可以实现多个接口。下面用代码来演示

public class Animal 
    protected String name;
    
    public Animal(String name)
        this.name = name;
    

然后我们再写一组接口,分别来表示“会飞的”“会跑的”“会游泳的”.

public interface IFlying 
    void fly();


public interface IRunning 
    void run();


public interface ISwimming 
    void swim();



那么接下来我们创建几个具体的动物类来接受并实现这些接口
比如,猫会跑👇

public class Cat extends Animal implements IRunning
    public Cat(String name) 
        super(name);
    
    
    @Override
    public void run() 
        System.out.println("小猫"+this.name+"正在跑");
    

鱼会游泳👇

public class Fish extends Animal implements ISwimming
    public Fish(String name)
     super(name);   
    
    
    @Override
    public void swim() 
        System.out.println("小鱼"+this.name+"正在游泳");
    

而青蛙即会跑又会游泳

public class Frog extends Animal implements IRunning,ISwimming
    public Frog(String name)
        super(name);
    
    
    @Override
    public void run() 
        System.out.println("青蛙"+this.name+"正在跑");
    

    @Override
    public void swim() 
        System.out.println("青蛙"+this.name+"正在游泳");
    

🍙 注意:一个类实现多个接口的时候,每个接口中的抽象方法都要去实现,除非类用abstract修饰,为抽象类

提示👉IDEA中使用ctrl + i 可以快速实现接口

还有一种动物水陆空三栖,它是大白鹅

public class Goose extends Animal implements IRunning,ISwimming,IFlying
    public Goose(String name) 
        super(name);
    

    @Override
    public void fly() 
        System.out.println(this.name+"正在飞");
    

    @Override
    public void run() 
        System.out.println(this.name+"正在跑");
    

    @Override
    public void swim() 
        System.out.println(this.name+"正在漂在水上");
    

这段代码展现了Java面向对象编程中最常见的用法:一个类继承了一个父类,然后同时实现多个接口
继承表达的含义是is-a,而接口表达的含义是具有xxx的特性

猫是一种动物,具有会跑的特性
青蛙是一种动物,即能跑也能有用
大白鹅也是一种动物,技能跑,也能游,还能飞

有了接口之后,类的使用者就不需要去关注具体的类的属性是否符合,而只需要关心某个类是否具有某个特性/功能,如果有,就可以实现对应的接口
那么我们现在实现一个走路的方法

public class TestDemo1 
    public static void walk(IRunning iRunning)
        System.out.println("我带着小伙伴去散步");
        iRunning.run();
    

    public static void main(String[] args) 
        Cat cat = new Cat("小猫");
        walk(cat);
        
        Frog frog = new Frog("小青蛙");
        walk(frog);
    

输出结果👇

只要是会跑的,带有跑这个属性特征的,都可以接受相应的对象

public class Robot implements IRunning
    private String name;
    public Robot(String name)
        this.name = name;
    
    @Override
    public void run() 
        System.out.println(this.name+"正在用轮子跑");
    

    public static void main(String[] args) 
        Robot robot = new Robot("机器人");
        walk(robot);
    



故输出结果为👇

2.6 🧋 接口之间的继承

在Java中,类和类之间是单继承的,一个类可以实现多个接口,接口与接口之间可以多继承。
即:用接口可以达到多继承的目的
接口可以继承一个接口,达到复用的效果。这里使用extends关键字

interface IRunning 
    void run();


interface ISwimming 
    void swim();


//两栖的动物,即能跑,也能游泳
interface IAmphibious extends IRunning ISwimming 



class Frog implements IAmphibious 
    ...

通过接口继承创建一个新的接口IAmphibious表示“两栖的”。
创建的Frog类就实现了这个两栖的接口

接口之间的继承就相当于把多个接口合并到了一起

2.7 🥘 接口使用的例子

我们在之前的数组中讲解过给数组排序,那么我们该如何给对象数组排序呢?
首先我们定义一个Student的类,然后重写一下String方法

public class Student 
    private String name;
    private

以上是关于Javaの一篇带你吃透接口的主要内容,如果未能解决你的问题,请参考以下文章

Java - 一篇带你了解类成员(基本数据类型/包装类/对象/数组)默认值

一篇带你搞懂 java 集合

一篇带你搞懂 java 集合

[java基础] 内部类@ 一篇带你玩透(超详解)

Java - 一篇带你解决 JDK Logger 日志配置失效问题

JVM - 一篇带你读懂 Java GC 日志(附 GC 耗时讲解)