前言
我们在上一节学了抽象类,get到了抽象类可以提取一些子类共有的属性和方法。通过这种方式,我们可以让代码逻辑更加的清晰,也能够使得我们的代码更加的健壮,但是抽象类需要被子类通过关键字extends继承,我们知道java中不能多继承。
那在java中除了抽象类,还有另外一种概念可以更好的去解决这种情况,就是:接口,interface
在Java编程语言中,接口(interface)是一种强大的特性,它允许我们定义一组方法的规范,但不提供这些方法的实现。接口是Java实现多态、抽象和模块化编程的基石之一。通过接口,Java实现了多重继承的效果,同时保持了类的单一继承结构。
正文
语法
在Java中,接口是一种引用类型,它是方法声明的集合,注意所有的方法都只是声明,没有具体的实现,也就是都是抽象方法。接口使用interface
关键字来声明,其中的方法默认是public abstract
的,即公开的且抽象的,所以在interface接口中声明方法通常public abstract
是可以省略的。
接口还可以包含常量,这些常量默认是public static final
的,所以在interface接口中声明常量通常public static final
是可以省略的。
我们之前已经学了变量,我们知道变量的应用是可以先声明然后再进行初始化赋值的。但是常量需要在声明的即赋值,并且常量一旦赋值后,常量的值便不能再被修改了。声明常量需要用到一个关键字final
,意思代表这个变量是最终的,不能变化的。通常我们声明常量的常量名用全大写的英文。
我们在学习字符串String的时候也了解到,String的不可变性,其实也是因为String类是被final修饰过的。
样例代码
public interface InterfacesDemo {
//定义一个常量DATA
public static final int DATA = 100;
//声明一个抽象方法echo
public abstract void echo();
//声明一个有两个参数的抽象方法add,
public abstract void add(int a, int b);
}
在上面的列子中, public static final和public abstract是可以省略的,如下所示:
public interface InterfacesDemo {
//定义一个常量DATA
int DATA = 100;
//声明一个抽象方法echo
void echo();
//声明一个有两个参数的抽象方法add,
void add(int a, int b);
}
接口实现
我们知道抽象类提取了子类的一些公共属性和行为,子类需要通过关键字extends继承抽象类,然后再去实现抽象方法体。
那对于同等作用的接口interface,也是需要类去实现它的。
在java中通过关键字implements
去实现接口。样例代码如下,比如我们实现上面定义的接口。
public class DemoDo implements InterfacesDemo{
@Override
public void echo() {
}
@Override
public void add(int a, int b) {
}
}
注意:因为interface接口中的方法都是被abstract修饰的方法,也就是抽象方法,所以子类实现接口的时候需要实现(重写)接口的所有抽象方法。
特点
- 接口不能被实例化。接口是一种规范或契约,需要类去通过implements去实现接口。
- 接口中的方法都是抽象的,即只有方法声明没有方法体。从Java 8开始,接口中可以包含默认方法和静态方法,这些方法可以有实现体。默认方法通过关键字default进行声明。
- 接口支持多重继承,即一个接口可以继承多个接口。
- 接口是Java实现多态的一种手段,通过接口引用可以指向实现了该接口的任何对象。
我们改一下上面的样例,修改成带有默认方法和静态方法应用的接口样例:
public interface InterfacesDemo {
//定义一个常量DATA
int DATA = 100;
//声明一个抽象方法echo
void echo();
//声明一个有两个参数的抽象方法add,
void add(int a, int b);
default void testDefault(){
System.out.println("这是接口的default方法");
}
static void testStatic(){
System.out.println("这是接口的static方法");
}
}
public class DemoDo implements InterfacesDemo{
@Override
public void echo() {
}
@Override
public void add(int a, int b) {
}
//在main函数中去调用接口中的静态方法,调用默认方法
public static void main(String[] args) {
InterfacesDemo.testStatic();
DemoDo demoDo = new DemoDo();
demoDo.testDefault();
}
}
接口的作用
- 定义契约:接口定义了项目结构,即一批同类型的类应该具备哪些方法。这有助于保持系统的一致性和规范性。
- 解耦:接口使得类的实现与接口分离,降低了类之间的耦合度。当需要修改某个类的实现时,只要它仍然遵循接口规范,就不会影响到其他依赖于该接口的类。
- 多态:通过接口引用,我们可以指向实现了该接口的任何对象,并在运行时动态地决定调用哪个实现类的方法。这提高了程序的灵活性和可扩展性。
- 模块化:接口有助于将系统划分为独立的模块,每个模块只关注自己的功能,并通过接口与其他模块进行交互。
- 设计框架:在框架设计中,接口经常用于定义框架的骨架和扩展点,允许开发者通过实现接口来扩展框架的功能。