>首页> IT >

带你搞懂Java的接口(实例详解)

时间:2022-04-19 17:10:46       来源:转载
本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于接口的相关问题,包括了接口的概念以及一些知识点汇总、语法规则、接口的使用以及接口的特性等等,下面一起来看一下,希望对大家有帮助。

推荐学习:《java视频教程》

接口

一图流

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

接口与类的相同处

接口与类的不同处

接口的一些特点

抽象类和接口的区别

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

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


那么在现实生活中,接口是什么呢?它可以是笔记本上的USB口,电源插座等那么这些接口在实现意义上以及使用标准上也有所不同

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

语法规则

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

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

接口的使用

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

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

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

//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();    }}

输出:

instanceof

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

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

接口的特性

接口类型是一种引用类型,但是不能直接new接口的对象
public class TestUSB {    public static void main(String[] args){        USB usb = new USB();    }}//编译会出错:USB是抽象的,无法实例化
接口中每一个方法都是public的抽象方法,即接口中的方法会被隐式地指定为public abstract(只能是public abstract,其他修饰符都会报错)
public interface USB {    //编译出错:此处不允许使用修饰符private    //或者是java: 缺少方法主体, 或声明抽象    private void openDevice();    void closeDevice();    //不同JDK版本编译器的标准是不一样的,报错也是不一样的}
接口中的方法是不能在接口中实现的,只能由实现接口的类来实现
public interface USB {    void openDevice();        //编译失败:因为接口中的方法默认为抽象方法    //Error:接口抽象方法不能带有主体}

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

重写接口中的方法时,不能使用default作为访问权限修饰
public interface USB {void openDevice();//默认为publicvoid closeDevice();//默认为public}public class Mouse implements USB {    @Override    void openDevice(){        System.out.println("打开鼠标");    }        //...}//这里编译会报错,重写USB中的openDevice方法时,不能使用默认修饰符

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

接口中可以含有变量,但是接口中的变量会被编译器自动隐式指定为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属性    }}
接口中不能有静态代码块和构造方法
public interface USB {    public USB(){        }//编译失败        {        }//编译失败        void openDevice();    void closeDevice();}
接口虽然不是类,但是接口编译完成之后的字节码文件的后缀格式也是.class如果类没有实现接口中的所有抽象方法,则类必须设置为抽象类JDK8中规定了接口中可以包含上面所说的default方法

实现多个接口

在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修饰,为抽象类

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

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);    }}

故输出结果为

接口之间的继承

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

interface IRunning {    void run();}interface ISwimming {    void swim();}//两栖的动物,即能跑,也能游泳interface IAmphibious extends IRunning ISwimming {}class Frog implements IAmphibious {    ...}

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

接口使用的例子

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

public class Student {    private String name;    private int score;    public Student(String name,int score){        this.name = name;        this.score = score;    }    @Override    public String toString() {        return "Student{" +                "name="" + name + "\"" +                ", score=" + score +                "}";    }}

我们再给定一个学生对象数组,根据这个对象数组中的元素进行排序这里我们按照分数降序排序

public class Student {    private String name;    private int score;    public Student(String name,int score){        this.name = name;        this.score = score;    }    @Override    public String toString() {        return "Student{" +                "name="" + name + "\"" +                ", score=" + score +                "}";    }    public static void main(String[] args) {        Student[] students = new Student[]{                new Student("A",95),                new Student("B",96),                 new Student("C",97),                new Student("D",98),        };    }}

那么按照我们之前的理解,数组中有一个可以供我们使用的sort方法,我们能否直接使用呢?

Arrays.sort(students);System.out.println(students);//运行结果:Exception in thread "main" java.lang.ClassCastException: class ClassArray.Student cannot be cast to class java.lang.Comparable (ClassArray.Student is in unnamed module of loader "app"; java.lang.Comparable is in module java.base of loader "bootstrap")at java.base/java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:320)at java.base/java.util.ComparableTimSort.sort(ComparableTimSort.java:188)at java.base/java.util.Arrays.sort(Arrays.java:1041)at ClassArray.Student.main(Student.java:36)

我们可以看到这里程序报错了,这里的意思是Student并没有实现Comparable的接口那么这里的sort是进行普通数字的比较,大小关系明确,而我们指定的是两个学生对象的引用变量,这样的大小关系的指定是错误的,我们需要额外去人为规定对象中的比较元素那么怎么实现呢?

public class Student implements Comparable{    private String name;    private int score;    public Student(String name,int score){        this.name = name;        this.score = score;    }    @Override    public String toString() {        return "Student{" +                "name="" + name + "\"" +                ", score=" + score +                "}";    }    @Override    public int compareTo(Student o) {        if (this.score>o.score){            return -1;//      如果当前对象应排在参数对象之前,则返回小于0的数字        } else if(this.score

那么我们在这里重写了compareTo的方法,自己定义了比较的规则,我们就自己再去写一个sort的方法,去调用这个compareTo方法,真正意义上实现对 对象数组的排序我们使用冒泡排序法

public static void sort(Comparable[] array){//        这里要注意,虽然接口不能实例化对象,//        但是接口类型的引用变量可以指向它的实现类对象//        这里的实现类对象就是实现了这个接口的对象//        例如Comparable[] comparable = new Student[3];//        所以这里的参数就可以用Comparable[] array来接收        for (int bound = 0;boundbound;cur--){                if (array[cur-1].compareTo(array[cur])>0){                    //这里就说明顺序不符合要求,交换两个变量的位置                    Comparable tmp = array[cur-1];                    array[cur-1] = array[cur];                    array[cur] = tmp;                }            }    }}

sort方法写好了,我们写一个main函数来测试一下

public static void main(String[] args) {        Student[] students = new Student[]{                new Student("A",95),                new Student("B",91),                new Student("C",97),                new Student("D",95),        };        System.out.println("sort前:"+Arrays.toString(students));        sort(students);        System.out.println("sort后:"+Arrays.toString(students));    }

运行结果

E:\develop\Java\jdk-11\bin\java.exe "-javaagent:E:\IDEA\IntelliJ IDEA Community Edition 2021.3.2\lib\idea_rt.jar=65257:E:\IDEA\IntelliJ IDEA Community Edition 2021.3.2\bin" -Dfile.encoding=UTF-8 -classpath E:\JAVAcode\gyljava\Interface\out\production\Interface ClassArray.Studentsort前:[Student{name="A", score=95}, Student{name="B", score=91}, Student{name="C", score=97}, Student{name="D", score=95}]sort后:[Student{name="C", score=97}, Student{name="A", score=95}, Student{name="D", score=95}, Student{name="B", score=91}]

那么我们如果想要按照名字排序呢?也是可以的

import java.util.Arrays;import java.util.Comparator;/** * Created with IntelliJ IDEA. * Description: Hello,I would appreciate your comments~ * User:Gremmie * Date: -04-13 * Destination:利用Comparable的接口实现对 对象数组 选择性排序的功能 */class Student implements Comparable{    public String name;    public int age;    public Student(String name, int age) {        this.name = name;        this.age = age;    }    @Override    public String toString() {        return "Student{" +                "name="" + name + "\"" +                ", age=" + age +                "}";    }    @Override    public int compareTo(Student o) {        return this.name.compareTo(o.name);    }}class AgeComparator implements Comparator {    @Override    public int compare(Student o1, Student o2) {        return o1.age-o2.age;    }}class NameComparator implements Comparator {    @Override    public int compare(Student o1, Student o2) {        return o1.name.compareTo(o2.name);    }}public class TestDemo {    public static void main(String[] args) {        Student[] students = new Student[3];        students[0] = new Student("zhangsan",19);        students[1] = new Student("lisi",8);        students[2] = new Student("abc",78);        AgeComparator ageComparator = new AgeComparator();        NameComparator nameComparator = new NameComparator();                        //这里的方法sort是Array里面自带的,非常方便,        //只需将我们写好的比较器传过去就好了        System.out.println("排序前:"+Arrays.toString(students));        Arrays.sort(students,nameComparator);        System.out.println("排序后:"+Arrays.toString(students));        Comparable[] studentComparable =students;    }    public static void main2(String[] args) {        /*Student students1 = new Student("zhangsan",19);        Student students2 = new Student("abc",78);        if(students2.compareTo(students1) > 0) {            System.out.println("fafaa");        }*/    }    public static void main1(String[] args) {        Student[] students = new Student[3];        students[0] = new Student("zhangsan",19);        students[1] = new Student("lisi",8);        students[2] = new Student("abc",78);        System.out.println("排序前:"+Arrays.toString(students));        Arrays.sort(students);        System.out.println("排序后:"+Arrays.toString(students));    }}

Clonable接口以及深拷贝

其作用如其名,是用来进行克隆的,Clonable是个很有用的接口。Object类中存在一个clone方法,调用这个方法可以创建出一个对象,实现“拷贝”。但是我们想要合法调用clone方法,就要先实现Clonable接口,否则就会抛出CloneNotSupportedException异常

/** * Created with IntelliJ IDEA. * Description: Hello,I would appreciate your comments~ * User:Gremmie * Date: -04-13 * Destination:利用Clonable的接口实现clone方法,克隆含对象的对象 */class Money implements Cloneable{    public double money = 19.9;    @Override    protected Object clone() throws CloneNotSupportedException {        return super.clone();    }}class Person implements Cloneable{    public int id = 1234;    public Money m = new Money();    @Override    public String toString() {        return "Person{" +                "id="" + id + "\"" +                "}";    }    @Override    protected Object clone() throws CloneNotSupportedException {        Person tmp = (Person) super.clone();        tmp.m = (Money) this.m.clone();        return tmp;        //return super.clone();    }}public class TestDemo {    public static void main(String[] args) {        Object o = new Person();        Object o2 = new Money();    }    public static void main1(String[] args) throws CloneNotSupportedException {        Person person1 = new Person();        Person person2 = (Person)person1.clone();        System.out.println(person1.m.money);        System.out.println(person2.m.money);        System.out.println("=========================");        person2.m.money = 99.99;        System.out.println(person1.m.money);        System.out.println(person2.m.money);    }}

推荐学习:《java视频教程》

以上就是带你搞懂Java的接口(实例详解)的详细内容,更多请关注php中文网其它相关文章!

关键词: 抽象方法 参数对象