Java必备基础十三——接口详细知识点归纳(与抽象类的对比)

在Java语言中,组成程序的基本接口有两种:类和接口,接口是一种与抽象类相类似的结构,接口在编译后也要生成一个子节码文件。


一.接口的定义

1.定义

接口为一种特殊的类,里面全部是由全局常量和公共的抽象方法(JDK8开始增加静态方法和默认方法,JDK 9开始增加私有方法和静态私有方法)所组成。

类是一种具体的实现,而接口定义的是一批类所要遵守的规范。接口不关心实现他的类的内部状态信息。如打印机的打印模板,任何打印机只要使用这个模板就要遵守这个模板的布局规范,而打印机如何打印和打印机的种类如何实现,无须关心。

接口是解决Java无法使用多继承的一种手段,但是接口在实际中更多的作用是制定标准的。

public interface Printable {
    int MAX_SIZE = 60;  //定义常量并赋值
    void print();   //定义抽象方法
    default void show1(){
        System.out.println("接口中的默认方法");
    }
    static void show2(){
        System.out.println("接口中的静态方法");
    }
    private static void show3(){
        System.out.println("接口中的私有静态方法");
    }
}

2.定义接口的语法

可以通过interface关键字来完成

[修饰符] interface Scratch {
    0~N个常量的定义...
    0~N个抽象方法的定义...
    0~N个默认方法的定义、...
    0~N个默认方法的定义、静态方法的或私有方法的定义...
}

3.定义接口需要注意以下几点

  • 修饰符可以是public或者缺省状态的,接口名称与类名的命名规则基本相同,一个接口可以继承多个父接口
  • 接口中定义的数据成员均是常量,名称全部采用大写字母(用下划线分隔单个标识里的多个单词)表示,定义的同时必须给这些常量赋值,否则会产生编译错误
  • 在定义接口时,抽象方法和数据成员一般不写修饰符。因为在编译时系统会自动给方法和数据成员加上public、static、final修饰符
  • 默认方法和静态方法在JDK8以上的版本才允许被定义。其中,静态方法必须使用static修饰,只能使用接口名调用;默认方法必须使用default修饰,无论程序是否指定,静态方法和默认方法总是public的
  • 私有方法是JDK9新增的,可以是静态方法也可以是实例方法,主要作为工具方法使用,为接口中的默认方法或静态方法提供支持
  • 接口中不能包含静态代块和构造方法
  • 与类相似,一个Java源文件中,可以有很多类和接口同时存在,可把接口当成一种特殊的类,所以一个Java源文件中最多只能有一个public修饰的接口或者一个public修饰的类存在,如果文件中定义了一个public接口则文件名必须与该接口名或者该类名称相同;同理如果Java源文件中定义了一个public类则文件名必须与该类名称相同;且一个源文件中类和接口名称不能相同

public class Printable {
    public static void main(String[] args) {
        System.out.println("Hello Word");
    }
}

interface P {
//     正确,因为P不为public修饰
}

public interface I {
//    错误,已经有一个public类了 ,删除public关键字就不会报错
}

public class C {
//    错误,已经有一个public类了
}

二.接口的继承

1.定义

接口的继承指的是接口继承接口,一个子接口可以继承多个父接口,使用关键字extends子接口将继承父接口中定义的常量以及所有抽象方法,并可以继承和重写接口中的默认方法

2.格式

[修饰符] interface 子接口名称 extends 父接口1,2,...,父接口n{
}

3.举例

interface X {
    int VAR_X = 6;
    void methodX();
}

interface Y{
    int VAR_Y=7;
    void methodY();
}

public interface Printable {
    int MAX_SIZE = 60;  //定义常量并赋值

    void print();   //定义抽象方法

    default void show1() {
        System.out.println("接口中的默认方法");
    }

    static void show2() {
        System.out.println("接口中的静态方法");
    }
}

interface Z extends  X,Y,Printable{
    int VAR_Z= 8;
    void methodZ();

    @Override
    default void show1() {
        System.out.println("重写接口中的默认方法");
    }
}

class TestInterface{
    public static void main(String[] args){
        System.out.println(Z.MAX_SIZE); // 常量可以直接调用,但是抽象方法
        System.out.println(Z.VAR_X);
        System.out.println(Z.VAR_Y);
        System.out.println(Z.VAR_Z);
    }
}

输出结果:
60
6
7
8

三.接口的实现

1.定义

继承一文中提到一个类只能继承一个父类,这是不够灵活的,可以通过实现多个接口来作补充。一个类可以实现一个或多个接口,关键字为implements

2.接口实现的语法

(1)格式一

class 类名 implements 接口名1,接口名2,...{
    ...
}

(2)格式二

class 类名 extends 父类名 implements 接口名1,接口名2,...{
    ...
}

3.接口实现举例

继承父类的extends需要写在实现接口implements之前。如果继承了抽象类,需要实现抽象类中的抽象方法,还需要实现接口中的所有抽象方法。

例如定义了一个接口

//定义一个打印接口
public interface Printable {
    int MAX_SIZE = 60;  //定义常量并赋值

    void print();   //定义抽象方法

    default void show1() {
        System.out.println("接口中的默认方法");
    }

    static void show2() {
        System.out.println("Printable接口中的静态方法");
    }
}

因为接口中只定义了人们关心的功能,并不考虑这些功能是如何实现的。所以Printable这个接口的类具有打印的能力。打印机能打印,所以打印机类能实现这个口;相机能打印,所以打印机类能实现这个接口;其他能够打印的也可以实现这个接口。

Java系统类库中标准借接口的命名大都以able结尾(表示具有完成某功能的能力),比如Comparable、Cloneable、Runable等。

下面是一个例子:

//定义一个打印接口
public interface Printable {
    int MAX_SIZE = 60;  //定义常量并赋值

    void print();   //定义抽象方法

    default void show1() {
        System.out.println("接口中的默认方法");
    }

    static void show2() {
        System.out.println("Printable接口中的静态方法");
    }
}

interface Z extends Printable{
    int VAR_Z= 8;
    void methodZ();

    @Override
    default void show1() {
        System.out.println("重写接口中的默认方法");
    }
}

class TestInterface implements Z{
    @Override
    public void print() {
        System.out.println("重写Z中继承于Printable的抽象方法");
    }

    @Override
    public void methodZ() {
        System.out.println("重写Z中的抽象方法");
    }

    @Override
    public void show1() {
        System.out.println("重写Printable中的默认方法");
    }

    public static void main(String[] args){
        System.out.println(Z.MAX_SIZE); // 常量可以直接调用,但是抽象方法
        System.out.println(Z.VAR_Z);
        TestInterface testInterface = new TestInterface();
        System.out.println(testInterface.MAX_SIZE); // 由于TestInterface实现了上面的接口,所以可以通过TestInterface类的对象调用接口中的常量方法
        System.out.println(testInterface.VAR_Z);
        testInterface.methodZ();
        testInterface.print();
        Printable.show2(); // 接口中的静态方法可以直接调用
    }
}

在TestInterface类中,对所实现的接口中定义的抽象方法都进行了重写,并且由于Z接口继承了Printable接口,TestInterface类实现了Z接口,所以TestInterface类要对Z接口和Printable接口中的所有抽象方法都进行了重写,并且,重写的方法要用public修饰,因为Java语言规定,在类中实现接口中定义的方法时不能比接口中定义的方法(接口中的抽象方法默认public修饰)有更低的访问权限

4.接口实现需要注意的语法

  • 实现接口的声明必须写在继承声明之后,即implementsextends后面
  • 一个类实现了接口,必须要实现接口中所有的抽象方法
  • 实现了接口的类中可以直接以接口名.常量名的方式引用接口中定义的数据成员

四.接口与抽象类的异同

1.相似点

  • 两者都可包含抽象方法。实现抽象类和接口的非抽象类必须实现这些抽象方法
  • 两者都不能用来实例化对象。可以声明抽象类和接口的变量,对抽象类来说,要用抽象类的非抽象子类来实例化该变量;对接口来说,要用实现接口的非抽象子类来实例化该变量
  • 两者的子类如果都没有实现抽象类(接口)中声明的所有抽象方法,则该子类就是抽象类
  • 两者都可以实现程序的多态性

2.不同点

  • 一个类只能继承一个直接父类,但是可以实现多个接口
  • 接口不包含构造方法,抽象类可包含
  • 接口的数据成员只能是静态常量,不能定义普通成员变量,抽象类都可
  • 接口中只能包含抽象方法、静态方法、默认方法和私有方法,不能为普通方法提供方法的实现,抽象类可以包含普通方法
  • 接口体现的是一种规范(打印机和相机都有打印的功能),与实现接口的子类中不存在父与子的关系;抽象类与其子类存在父与子的关系(圆形和方形都是一种形状)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>