一、接口
- 接口:是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么接口的内部主要就是封装了方法,包含抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法(JDK 9)。
- 接口的定义:它与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class文件,但一定要明确它并不是类,而是另外一种引用数据类型。
- 接口的使用:它不能创建对象,但是可以被实现( implements ,类似于被继承)。一个实现接口的类(可以看做是接口的子类),需要实现接口中所有的抽象方法,创建该类对象,就可以调用方法了,否则它必须是一个抽象类。
Tips:引用数据类型:数组,类,接口等。
二、定义格式
语法格式:
【权限修饰符】 interface 接口名称 {
接口的成员列表如下:
// 抽象方法
// 默认方法
// 静态方法
// 私有方法
}
1、JDK1.7及以前接口成员有两种:静态常量和抽象方法(JDK7+)
全局的静态的常量:接口当中也可以定义“成员变量”,但是必须使用public static final三个关键字进行修饰(可省略),其实就是接口中的【常量】。
公共的抽象方法:使用publc abstract 关键字修饰,(可以省略)没有方法体。该方法供子类实现使用。
语法格式:
public static final 数据类型 变量名 = 值;
public abstract 返回值类型 方法名称(参数列表);
Demo:
1 public interface InterFaceName {
2 public static final long MAX_SPEED = 7900000; //常量
3 public abstract void method(); //抽象方法
4 }
Tips:一旦使用final关键字进行修饰,说明不可改变。
注意事项:
a、接口当中的常量,可以省略 public static final,注意:不写也照样是这样。
b、接口当中的常量,必须进行赋值;不能不赋值。
c、接口中常量的名称,使用完全大写的字母,用下划线进行分隔。(推荐命名规则)
2、JDK1.8以后接口有增强两个成员:默认方法和静态方法(JDK8+)
默认方法:使用 default 修饰,不可省略,供子类调用或者子类重写。
语法格式:
public default 返回值类型 方法名称(参数列表) {
方法体
}
静态方法:使用public static 修饰,不可省略,供接口直接调用。
Demo:
1 public interface InterFaceName {
2 public default void method() {
3 // 执行语句
4 }
5 public static void method2() {
6 // 执行语句
7 }
8 }
扩展:
(1)为什么 Java8 要允许接口中定义静态方法?
因为JDK发展了一段时间后,发现类库中,多了很多的成组的API,如Array和Arrays类,Collection接口和Collections工具类。
一般工具类都是静态方法,这些静态方法,基本上都是为前面这个对应接口服务的。当把这样的静态方法直接挪到接口中定义就好了,减少了这样的工具类的出现。
(2)为什么 Java8 要允许接口中定义默认方法?
因为有的时候,一个接口它的大多数实现类对接口的抽象方法的实现代码是一样的,那样写好几次就非常麻烦。即相当于,默认方法是原来的抽象方法有了一个默认实现。
如果实现类的实现和接口一样,就不需要重写,如果不一样就重写即可。
3、JDK1.9以后增加两个接口成员:私有方法和私有静态方法(JDK9+)
私有方法:使用 private 修饰,供接口中的默认方法或者静态方法调用。
Demo:
1 public interface InterFaceName {
2 private void method() {
3 // 执行语句
4 }
5 }
三、基本的实现
1、实现的概述
类与接口的关系为实现关系,即类实现接口,该类也可以称为接口的实现类,也可以称为接口的子类。
实现的动作似继承,格式相仿,只是关键字不同,实现使用 implements 关键字。
非抽象子类实现接口:
-
- 必须重写接口中所有的抽象方法。
- 继承了接口的默认方法,即可以直接调用,也可以重写。
- 必须重写接口中所有的抽象方法。
实现格式:
class 类名 implements 接口名 {
// 重写接口中抽象方法【必须】
// 重写接口中默认方法【可选】
}
2、抽象方法的使用
接口中的抽象方法必须全部实现。
Demo:
1 // 定义接口: 2 public interface LiveAble { 3 // 定义抽象方法 4 public abstract void eat(); 5 public abstract void sleep(); 6 } 7 8 // 定义实现类 9 public class Animal implements LiveAble { 10 @Override 11 public void eat() { 12 System.out.println("吃东西"); 13 } 14 @Override 15 public void sleep() { 16 System.out.println("晚上睡"); 17 } 18 }
3、默认方法的使用
可以继承,可以重写,二选一,但是只能通过实现类的对象来调用。
(1)继承默认方法
Demo:
1 // 定义接口 2 public interface LiveAble { 3 public default void fly(){ 4 System.out.println("天上飞"); 5 } 6 } 7 8 // 定义实现类 9 public class Animal implements LiveAble { 10 // 继承,什么都不用写,直接调用 11 } 12 13 // 测试类 14 public class InterfaceDemo { 15 public static void main(String[] args) { 16 // 创建子类对象 17 Animal a = new Animal(); 18 // 调用默认方法 19 a.fly(); 20 } 21 } 22 输出结果: 23 天上飞
(2)重写默认方法
1 // 定义接口 2 public interface LiveAble { 3 public default void fly(){ 4 System.out.println("天上飞"); 5 } 6 } 7 8 // 定义实现类 9 public class Animal implements LiveAble { 10 @Override 11 public void fly() { 12 System.out.println("自由自在的飞"); 13 } 14 } 15 16 // 定义测试类 17 public class InterfaceDemo { 18 public static void main(String[] args) { 19 // 创建子类对象 20 Animal a = new Animal(); 21 // 调用重写方法 22 a.fly(); 23 } 24 } 25 输出结果: 26 自由自在的飞
4、静态方法的使用
静态与 .class 文件相关,只能使用接口名调用,不可以通过实现类的类名或者实现类的对象调用。
语法格式:
public static 返回值类型 方法名称(参数列表) {
方法体
}
Demo:
1 // 定义接口 2 public interface LiveAble { 3 public static void run(){ 4 System.out.println("跑起来~~~"); 5 } 6 } 7 8 // 定义实现类 9 public class Animal implements LiveAble { 10 // 无法重写静态方法 11 } 12 13 // 定义测试类 14 public class InterfaceDemo { 15 public static void main(String[] args) { 16 // Animal.run(); // 【错误】无法继承方法,也无法调用 17 LiveAble.run(); // 18 } 19 } 20 输出结果: 21 跑起来~~~
5、私有方法的使用
-
-
- 私有方法:只有默认方法可以调用;
- 私有静态方法:默认方法和静态方法可以调用;
-
语法格式:
private 返回值类型 方法名称(参数列表){ 方法体} 普通私有方法
private static 返回值类型 方法名称(参数列表) { 方法体} 静态私有方法
如果一个接口中有多个默认方法,并且方法中有重复的内容,那么可以抽取出来,封装到私有方法中,供默认方法去调用。
Demo:
1 public interface LiveAble { 2 default void func(){ 3 func1(); 4 func2(); 5 } 6 private void func1(){ 7 System.out.println("跑起来~~~"); 8 } 9 private void func2(){ 10 System.out.println("跑起来~~~"); 11 } 12 }
四、接口的多实现(冲突问题)
在继承体系中,一个类只能继承一个父类。而对于接口而言,一个类是可以实现多个接口的,这叫做接口的多实现。并且,一个类能继承一个父类,同时实现多个接口。
实现格式:
class 类名 [extends 父类名] implements 接口名1,接口名2,接口名3... {
// 重写接口中抽象方法【必须】
// 重写接口中默认方法【不重名时可选】
}
1、抽象方法
接口中,有多个抽象方法时,实现类必须重写所有抽象方法。如果抽象方法有重名的,只需要重写一次。
Demo:
1 // 定义接口 2 interface A { 3 public abstract void showA(); 4 public abstract void show(); 5 } 6 interface B { 7 public abstract void showB(); 8 public abstract void show(); 9 } 10 11 //定义实现类 12 public class C implements A,B{ 13 @Override 14 public void showA() { 15 System.out.println("showA"); 16 } 17 @Override 18 public void showB() { 19 System.out.println("showB"); 20 } 21 @Override 22 public void show() { 23 System.out.println("show"); 24 } 25 }
2、默认方法
当一个类同时实现了两个甚至更多个接口时,这些个接口中出现了方法签名相同的默认方法时,
必须在这个类中,做出选择:
(1)保留其中一个,放弃另一个;
(2)两者都不用,完全重写一个;
Demo:
1 interface A{
2 public default void test(){
3 System.out.println("aaa");
4 }
5 }
6 interface B{
7 public default void test(){
8 System.out.println("bbb");
9 }
10 }
11 class C implements A,B{
12 //选择一:保留其中一个,放弃另一个
13 A.super.test(); //保留A接口的实现
14 B.super.test(); //保留B接口的实现
15 }
16
17 class C1 implements A,B{
18 //选择二:两者都不用,完全重写一个
19 public void test(){
20 System.out.println("ccc");
21 }
22 }
3、静态方法
接口中,存在同名的静态方法并不会冲突,原因是只能通过各自接口名访问静态方法。
4、优先级的问题
当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的方法签名一样的方法,怎么办?
如何选择?
(1)默认选择:编译器默认选择父类中的方法
(2)改选保留接口的
(3)完全自己重写
Demo:
1 class Father{
2 public void test(){
3 System.out.println("ffff");
4 }
5 }
6 interface D{
7 public default void test(){
8 System.out.println("dddd");
9 }
10 }
11 class Son1 extends Father implements D{
12 //选择一:默认选择, 保留父类的
13 }
14
15 class Son2 extends Father implements D{
16 //选择二:改选接口的
17 public void test() {
18 D.super.test();
19 }
20 }
21
22 class Son3 extends Father implements D{
23 // 完全自己重写
24 public void test() {
25 System.out.println("ssss");
26 }
27 }
五、接口的多继承
一个接口能继承另一个或者多个接口,这和类之间的继承比较相似。接口的继承使用 extends 关键字,子接口继承父接口的方法。
如果父接口中的默认方法有重名的,那么子接口需要重写一次。
Demo:
1 //定义父接口
2 interface A {
3 public default void method(){
4 System.out.println("AAAAA");
5 }
6 }
7 interface B {
8 public default void method(){
9 System.out.println("BBBBB");
10 }
11 }
12
13 // 定义子接口
14 interface D extends A,B{
15 @Override
16 public default void method() {
17 System.out.println("DDDDD");
18 }
19 }
Tips:子接口重写默认方法时,default 关键字可以保留;子类重写默认方法时,default 关键字不可以保留。
六、成员特点
- 接口中,无法定义成员变量,但是可以定义常量,其值不可以改变,默认使用 public static final 修饰。
- 接口中,没有构造方法,不能创建对象。
- 接口中,没有静态代码块。
- 一个类如果直接继承父类当中的方法,和接口当中的默认方法产生了冲突,优先用父类当中的方法。
七、接口的特点
1、接口是标准,就是用来被遵守的,即就是用来被实现的,那么要求实现类在实现接口时,必须实现/重写所有的抽象方法,否则这个实现类就得是一个抽象类;
2、接口也是不能直接创建对象的;
3、接口类型的变量与实现类的对象构成多态引用;
4、一个类继承父类时,Java只支持单继承,但是一个类在实现接口时,可以同时实现多个接口;
5、一个类如果同时继承父类,又实现接口时,要求继承在前,实现在后;
【修饰符】 class 实现类 extends 父类 implements 父接口们{}
6、在Java中,接口还可以继承接口;
【权限修饰符】 interface 子接口 extends 父接口们{ }