> 文章列表 > Java中的接口

Java中的接口

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 { }