🌿🌿🌿跟随博主脚步,从这里开始→博主主页🌿🌿🌿
接口介绍
- 接口
- 概述
- 接口定义
- 接口的实现
- 实战演练
- 👅接口的继承
- 实战演练
- 实战演练
- 接口的类型
- 常量
- 实战演练
- 静态方法
- 默认方法
- 解决默认方法冲突
- 实战演练
接口
概述
Java语言中所有的类都处于一个类层次结构中。
除Object类以外,所有类都只有一个直接父类,即子类与父类之间是单继承的关系,但不允许多重继承。
为了实现多重继承,java语言通过接口使得处于不同层次、甚至互不相关的类具有相同的行为。
接口定义
- 接口定义了一种可以被类层次中任何类实现的行为的协议
- 接口是常量、抽象方法、默认方法和静态方法的集合体
- 接口可以实现多重继承
- 接口声明使用interface关键字
- 接口定义,包含接口声明和接口体两部分
[public或者省略] interface 接口名称 [extends 父接口名列表]
{
[public][static][final] 数据类型 成员变量名=常量;
……
[public][abstract] 返回值的数据类型 方法名(参数表);
……
[public] static 返回值的数据类型 方法名(参数表)
{
方法体
}
……
[public] default 返回值的数据类型 方法名(参数表)
{
方法体
}
……
}
例:
public interface Eatable {
接口被看作是一种特殊的类型。每个接口都被编译为独立的字节码文件。
//抽象方法
public abstract String howtoEat();
}
接口与抽象类相似:
接口可以作为引用变量数据类型或类型转换的结果;
接口与抽象类一样,不能用new运算符创建接口实例。
接口的抽象方法只有声明,没有实现。
抽象方法也可以省略修饰符,省略修饰符编译器自动加上public、abstract。
- 接口的UML表示
- 接口通常表示某种能力,因此接口名后缀通常是able。
接口的实现
接口的实现:利用接口的特性来建造类的过程。类似于继承,但不是extends,而是使用implements。
接口实现的语法格式:
class 类名称 implements 接口名表
{
……
}
👀一个类实现一个接口应注意的问题:
- 如果实现某接口的类不是abstract的抽象类,则在类的定义部分必须实现指定接口的所有抽象方法。
- 一个类在实现某接口的抽象方法时,必须使用完全相同的方法头。
- 接口中抽象方法被指定为public,所以类在实现方法时,必须显示地使用public修饰符。
- 接口可以作为一种引用类型来使用,可以声明接口类型的变量或数组,并用它来访问实现该接口的类的对象。
(通过接口类型的变量可以访问类所实现的接口的方法)
实战演练
【例】Orange实现Eatable接口。
public interface Eatable {
//抽象方法
public abstract String howtoEat();
}
public class Orange
@Override
public String howtoEat(){
return “Make Orange Juice”
}
}
👅接口的继承
- 定义一个接口时可通过extends关键字声明该新接口是某个已存在的父接口的派生接口。
- 与类继承的区别:一个接口可以有一个以上的父接口,它们之间用逗号隔开,形成父接口列表。
- 新接口将继承所有父接口的常量、抽象方法和默认方法,但不能继承父接口的静态方法(也不能被实现类所继承)。
- 多重继承:一个子类可以有一个以上的直接父类,该子类可以继承它所有直接父类的成员。
- Java语言虽不支持多重继承,但可以利用接口间接地解决多继承问题。
- 一个类只能有一个直接父类,但是它可以同时实现若干个接口(Java中接口的主要作用是可以帮助实现多重继承。)。一个类实现多个接口时,在implements子句中用逗号分隔各个接口名。
实战演练
【例】接口继承多个接口。CC接口继承AA接口和BB接口
public interface AA {
int STATUS = 100;
public abstract void display();
}
public interface BB {
public abstract void show();
public default void print(){
System.out.println("这个是接口BB的默认方法");
}
}
public interface CC extends AA, BB{
int NUM = 3;
}
public class DD implements CC {
public void display() {
System.out.println("接口AA的display方法");
}
public void show() {
System.out.println("接口BB的show方法");
}
public static void main(String[] args) {
DD dd = new DD();
System.out.println(DD.STATUS);
dd.show();
dd.print();
AA aa = new DD();
aa.display();
}
}
运行结果:
解释代码:
上述AA、BB、CC接口与DD类之间的关系如图所示;图中虚线表示接口实现。
接口是允许多继承的,而类只能实现单继承。
实战演练
【例】类实现多个接口。AB类实现AA接口和BB接口
public class AB implements AA, BB{
public void display(){
System.out.println("接口AA的display方法");
}
public void show(){
System.out.println("接口BB的show方法");
}
}
类实现多个接口需实现每个接口中的抽象方法。接口中的常量和默认方法都被继承了,但接口中的静态方不被继承
接口的类型
接口也是一种引用类型,任何实现该接口的实例都可以存储在该接口类型的变量中。
AA aa = new DD(); // 向上自动类型转换
BB bb = new DD();
CC cc = new DD();
当通过接口对象调用某个方法时,Java运行时系统确定该调用哪个类中的方法。
aa.display(); // 调用实现类的方法
bb.show();
cc.print(); // 调用继承的默认方法
常量
定义在接口中的任何变量都自动加上public、final、static属性,因此它们都是常量,常量的定义可以省略修饰符,下面三行代码效果相同。
int STATUS = 100;
public int STATUS = 100;
public final static int STATUS = 100;
不推荐在接口中定义常量,使用枚举类型描述一组常量集合比接口常量更好。
实战演练
1.设计一个名为Swimmable的接口,其中包含void swim()方法,设计另一个名为Flyable的接口,其中包含void fly()方法。
2.定义一个Duck类实现上述两个接口。
// Swimmable接口
interface Swimmable {
void swim();
}
// Flyable接口
interface Flyable {
void fly();
}
// Duck类实现Swimmable和Flyable接口
class Duck implements Swimmable, Flyable {
// 实现Swimmable接口的swim方法
@Override
public void swim() {
System.out.println("The duck is swimming.");
}
// 实现Flyable接口的fly方法
@Override
public void fly() {
System.out.println("The duck is flying.");
}
// 可以在Duck类中添加其他方法和属性
}
// 测试类
public class Main {
public static void main(String[] args) {
Duck duck = new Duck();
duck.swim(); // 调用swim方法
duck.fly(); // 调用fly方法
}
}
在这个例子中,Swimmable
和Flyable
是两个接口,它们分别定义了swim
和fly
方法。Duck
类通过implements
关键字实现了这两个接口,因此它必须提供这两个方法的具体实现。在main方法中,我们创建了一个Duck
对象,并调用了它的swim
和fly
方法,输出了相应的信息。
静态方法
- 在Java 8中,可以在接口中定义静态方法,定义静态方法使用static关键字,默认的访问修饰符是public。
- 接口的静态方法不能被子接口继承,也不被实现类继承。
- 接口中的静态方法不能被子接口和实现类继承,访问形式为:接口名.静态方法名( )。
public interface SS {
int STATUS = 100;
public static void display() {
System.out.println(STATUS);
}
}
默认方法
- 接口中的默认方法用default修饰符来定义,默认方法可以被子接口或被实现该接口的类所继承。访问形式为:对象名.默认方法名( )。
- 子接口中若定义名称相同的默认方法,则父接口中的默认方法被隐藏。
public interface BB {
public void show();
public default void print(){
System.out.println("这个是接口BB的默认方法");
}
}
解决默认方法冲突
- 如果子接口中定义了与父接口同名的常量或者相同的方法,则父接口中的常量被隐藏,方法被覆盖。
- 但在接口的多重继承中可能存在常量名或方法名重复的问题,即名字冲突问题。
- 对于常量,若名称不冲突,子接口可以继承多个父接口中的常量,如果多个父接口中有同名的常量,则子接口不能继承,但子接口中可以定义一个同名的常量。
- 对于多个父接口中存在同名的方法时,此时必须通过特殊的方式加以解决。
- 在多个父接口的实现类中解决同名默认方法的名字冲突问题有两种方法:一种是提供同名方法的一个新实现;另一种是委托一个父接口的默认方法。
- 如果两个父接口有一个提供的不是默认方法,而是抽象方法,则在实现类中提供同名方法的一个新实现即可。
- 如果一个类继承了一个父类并实现了一个接口,而从父类和接口中继承了同名的方法,此时采用“类比接口优先”的原则,即只继承父类的方法,而忽略来自接口的默认方法。
实战演练
【例】在两个接口Person和Identified中定义的同名默认方法getID ( ),在实现类中委托其中一个父接口的默认方法
public interface Person {
public String getName();
public default int getID(){
return 0;
}
}
public interface Identified {
public default int getID(){
return Math.abs(hashCode());
}
}
public class Employee implements Person, Identified {
String name;
@Override
public String getName(){
return this.name;
}
public int getID(){
return Identified.super.getID();
} // 为getID()方法提供一个新的实现
}
博主用心写,读者点关注,互动传真情,知识不迷路。