Java中的接口
1. 定义
接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合
,接口通常以interface来声明。
一个类通过继承接口的方式,从而来继承接口的抽象方法。
接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法
。
除非实现接口的类是抽象类,否则该类要定义接口中的所有方法
。
接口无法被实例化,但是可以被实现
。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类
。另外,在Java中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。
2. 接口与类的相同点
一个接口可以有多个方法。
接口文件保存在 .java 结尾的文件中,文件名使用接口名。
接口的字节码文件保存在 .class 结尾的文件中。
接口相应的字节码文件必须在与包名称相匹配的目录结构中。
3. 接口与类的区别
接口不能用于实例化对象。
接口没有构造方法。
接口中所有的方法必须是抽象方法
,Java8之后接口中可以使用 default 关键字修饰的非抽象方法。
接口不能包含成员变量,除了static和final变量。
接口不是被类继承了,而是要被类实现。
通过接口可以实现Java的多继承。
4. 抽象类和接口的区别
a. 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
b. 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的
。
c. 接口中不能含有静态代码块
以及静态方法(用 static 修饰的方法,java8中可以),而抽象类是可以有静态代码块和静态方法。
d. 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
5. 接口特性
a. 接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字;
b. 接口中的方法都是公有的;
c. 接口中的所有方法都是 public abstract
的,因此声明方法时,可以省略public abstract;
d. 与public类一样,public接口也必须定义在于接口同名的文件中;
e. 在接口中声明方法时,不能使用native,final,synchronize,protected等说明符;
f. 在接口中也可以有数据成员,这些成员默认是都是public static final
的,因此在声明时,可以直接省略;
g. 接口中的数据成员必须赋初值,且此值不能再被更改;
interface Hello {public static final double f1 = 0.0; // 接口中的变量必须赋初值, 否则报错public static double f2 = 0.0;public final double f3 = 0.0;public int num = 0;public char ch = 'c';int test = 100;public abstract void show();void hello(); // 省略了public abstractpublic static void display1() {} // 静态方法 default void display2() {} // 默认方法private void display3() {} // 私有方法private static void display4() {} // 静态的私有方法
}/*
* Java中的类不具备多继承,但是接口可以多继承。
* */
interface sing {public abstract void sing1();public abstract void sing2();
}
interface play {public abstract void play1();public abstract void play2();
}
interface Multi extends sing, play {public abstract void happy();
}class Real implements Multi {@Overridepublic void play1() {}@Overridepublic void play2() {}@Overridepublic void sing1() {}@Overridepublic void sing2() {}@Overridepublic void happy() {}
}
6. 接口的实现
当类实现接口的时候,类要实现接口中所有的方法
。否则,类必须声明为抽象的类
。
类使用implements
关键字实现接口。
interface Animal {void eat();void say();default void sleep() {System.out.println("animal can sleep.");}
}class Fish implements Animal {@Overridepublic void eat() {}@Overridepublic void say() {}
}
7. 接口的继承
一个接口能继承另一个接口,和类之间的继承方式比较相似。
接口的继承使用extends
关键字,子接口继承父接口的方法。
接口可单继承,也可以多继承。
/
* 接口的单继承
* */
interface Animal {void eat();void say();default void sleep() {System.out.println("animal can sleep.");}
}interface FlayableAnimal extends Animal {void flay();
}
/
* 接口的多继承
* 在Java中,类的多继承是不合法,但接口允许多继承。
* 在接口的多继承中extends关键字只需要使用一次,在其后跟着继承接口。
* */
interface Animal {void eat();void sleep();
}
interface Speakable {void say();
}interface AnimalToys extends Animal, Speakable
{void dance();
}
8. 标记接口
最常用的继承接口是没有包含任何方法的接口。
标记接口是没有任何方法和属性的接口
。它仅仅表明它的类属于一个特定的类型,供其他代码来测试允许做一些事情。
标记接口作用:简单形象的说就是给某个对象打个标(盖个戳),使对象拥有某个或某些特权。
例如:java.awt.event 包中的 MouseListener 接口继承的 java.util.EventListener 接口定义如下:
package java.util;
public interface EventListener
{}
没有任何方法的接口被称为标记接口。标记接口主要用于以下两种目的:
a.
建立一个公共的父接口:
正如EventListener接口,这是由几十个其他接口扩展的Java API,你可以使用一个标记接口来建立一组接口的父接口。
例如:当一个接口继承了EventListener接口,Java虚拟机(JVM)就知道该接口将要被用于一个事件的代理方案。
b.
向一个类添加数据类型:
这种情况是标记接口最初的目的,实现标记接口的类不需要定义任何接口方法(因为标记接口根本就没有方法),但是该类通过多态性变成一个接口类型。
9. 接口的默认方法
/
* 接口的默认方法:(Java8新增)
* 1. 前面说过,接口中的方法是抽象的,某个类实现了接口,就要实现接口中的所有方法,
* 如果没有完全实现接口中的方法,那么这个类就必须声明为抽象类。
* 此时有这样一种场景:
* 在接口和实现类编写完以后,如果需要在接口中新增一个方法,那么该接口的实现类也必须重新编码。
* 那如果实现该接口的类还比较多,那么修改起来就比较痛苦了,为此,Java8中新增了接口的默认方法这一特性,
* 允许你在接口中定义带有默认实现的方法,默认方法需要用default来声明。
* 为原有的接口添加新的默认方法,不会影响到现有的实现类。
* 2. 另外注意:类也可以重写接口的默认方法。
* 3. 注意:接口中的默认方法【必须给出函数体】,否则报错。
* */
interface Animal {void sing();void swim();default void hello() {System.out.println("HelloWorld.");}
}
class Additional implements Animal {@Overridepublic void sing() {}@Overridepublic void swim() {}// 类重写接口的默认方法,可以重写,也可以不重写@Overridepublic void hello() {Animal.super.hello();}
}
/* 接口中默认方法的同名问题:* 类在实现多个接口时,如果存在多个同名的默认方法,那就会产生歧义性。* 此时需要在类中重写同名方法,否则报错。* 如下例所示:如果在类son中不重写 同名方法happy(), 那么报错。* * */
interface father {default void happy() {System.out.println("father is happy.");}
}
interface mother {default void happy() {System.out.println("mother is happy.");}
}
class son implements father, mother {@Overridepublic void happy() {father.super.happy();mother.super.happy();System.out.println("son is happy.");}
}
10. 接口的静态方法
/* 接口的静态方法:(Java8新增)* 注意:接口中的静态方法【必须给出函数体】,否则报错;* 在接口中定义的静态方法,只能通过该接口名来调用,通过子接口名或者实现类名来调用都是不允许的。* 说明这与类当中的静态方法的调用还是有一定区别的。* */
class class1 {public static void show() {System.out.println("HelloWorld");}
}
class class2 extends class1 {public class2() {class1.show();class2.show();super.show();}
}interface in1 {static void show() {System.out.println("HelloWorld");}
}
class _in1 implements in1 {public _in1() {in1.show();
// _in1.show(); // error}
}
11. 接口的私有方法
/* 接口的私有方法:(Java9新增)* 为了解决接口中代码冗余的问题,Java9为接口新增了私有方法,可以是普通的私有方法,也可以是私有的静态方法。* 注意:接口中的私有方法【必须给出函数体】,否则报错; * */
interface Log {// 普通私有方法private void log(String message, String prefix) {openFile();System.out.println(message + " : " + prefix);closeFile();}// 静态私有方法private static void openFile() {System.out.println("open the file.");}private static void closeFile() {System.out.println("close the file.");}// 默认方法default void logDebug(String message) {log(message, "DEBUG");}default void logInfo(String message) {log(message, "INFO");}default void logWarn(String message) {log(message, "WARN");}default void logError(String message) {log(message, "ERROR");}
}
class MyLogger implements Log { }