接口
在抽象类中,抽象方法本质上是定义一种规范:即规定抽象的规范,从而确保所有子类都能有相同的实现。
abstract class Person {
public abstract void run();
public abstract String getName();
}
如果一个抽象类没有字段,所有方法都是抽象方法,那么此时可以把抽象类改写为 interface
接口:
interface Person {
public abstract void run();
public abstract String getName();
}
所谓 interface
,就是比 抽象类还要抽象的抽象接口。接口中可以定义字段和方法:
- 定义字段:必须使用 public static final 修饰;
- 定义方法:必须使用 public abstract 修饰;
由于所有的字段和方法修饰符都是固定的,所以修饰符可以省略不写。
interface Person {
//public static final String name = "";
String name = "";
//public static final int age = 0;
int age = 0;
//public abstract void run();
void run();
//public abstract String getName();
String getName();
}
类实现接口
当一个 class
实现一个 interface
时,需要使用 implements
关键字。
class Student implements Person {
private String name;
public Student(String name) {
this.name = name;
}
//必须要实现接口中定义的方法
@Override
public void run() {
System.out.println("Student running.");
}
@Override
public String getName() {
return this.name;
}
}
在 java 中,一个类只能继承自另一个类,不能继承多个类。但是,一个类可以继承自多个 interface
。
class Student implements Person, Person2, Person3 {
//...
}
同时,当子类即继承了父类,又实现了接口时,一般先继承父类,再实现接口:
interface Person {
void run();
String getName();
}
class father {
}
class Student extends father implements Person {
@Override
public void run() {
}
@Override
public String getName() {
return "";
}
}
接口继承接口
一个 interface
接口可以使用 extends
关键字继承另一个 interface
接口。
interface Hello {
void hello();
}
interface Person extends Hello {
void run();
String getName();
}
此时,Person
接口实际上拥有了 3 个抽象方法,其中 hello() 来自于继承的接口。
JDK8新特性
静态方法
JDK8 以后,接口中可以定义静态方法,该方法只能接口自己调用。
public static void main(String[] args) {
Person.method();
}
interface Person {
public static void method() {
System.out.println("我是静态方法");
}
}
默认方法
JDK8 以后,接口中可以使用 default
关键字定义默认方法,子类实现接口时,可以不用立即实现默认方法,在需要的时候实现即可。
public static void main(String[] args) {
Student student = new Student();
//Student子类没有实现 method 方法,这时候会走接口中定义的 method 方法
student.method(); //我是Person接口中的默认方法.
}
interface Person {
public default void method() {
System.out.println("我是Person接口中的默认方法.");
}
}
class Student implements Person {
}
public static void main(String[] args) {
Student student = new Student();
//Student子类实现了 method 方法,这时候会子类中的 method 方法
student.method(); //我是Student子类的默认方法.
}
interface Person {
public default void method() {
System.out.println("我是Person接口中的默认方法.");
}
}
class Student implements Person {
@Override
public void method2() {
System.out.println("我是Student子类的默认方法.");
}
}
接口冲突
当 A 接口中有 method 方法,而 B 接口中也有一个和 A 一模一样的 method 方法时,实现类即继承了 A,也继承了 B,这时候实现类就会报错,因为不知道 method 方法到底是继承自谁的,所以,此时实现类就必须手动重写 method 方法。
interface Person {
public default void method() {
System.out.println("Person");
}
}
interface Person2 {
public default void method() {
System.out.println("Person2");
}
}
class Student implements Person, Person2 { //报错: 不知道要继承谁的 method 方法
}
class Student implements Person, Person2 { //正确: 因为重写了 method 方法,调用时就会走 Student 类的方法
@Override
public void method() {
System.out.println("student");
}
}
这种情况下,如果 Student 类的 method 方法中,就想要调用 父接口中的 method 方法,可以使用 Person.super.method
方式。
public static void main(String[] args) {
Student student = new Student();
student.method(); //Person Person2都打印
}
interface Person {
public default void method() {
System.out.println("Person");
}
}
interface Person2 {
public default void method() {
System.out.println("Person2");
}
}
class Student implements Person, Person2 {
@Override
public void method() {
Person.super.method();
Person2.super.method();
}
}
类和接口优先级
当一个类即继承了父类,又实现了接口,而父类中和接口中存在相同的方法,这时候 父类的优先级更高。
public class interfaceTest {
public static void main(String[] args) {
Student student = new Student();
//父类的优先级更高
student.method2(); //Person2
}
}
interface Person {
public default void method2() {
System.out.println("Person");
}
}
class Person2 {
public void method2() {
System.out.println("Person2");
}
}
class Student extends Person2 implements Person {
}
抽象类和接口区别
区别点 | 抽象类 | 接口 |
---|---|---|
定义 | 可以包含抽象方法的类 | 主要是抽象方法和全局常量的集合 |
组成 | 构造方法、抽象方法、普通方法、常量、变量 | 常量、抽象方法(jdk8 以后,默认方法、静态方法) |
使用 | 子类继承抽象类(extends) | 子类实现接口(implements) |
关系 | 抽象类可以实现多个接口 | 接口不能继承抽象类,但允许继承多个接口 |
常见设计模式 | 模板方法 | 简单工厂、工厂方法、代理模式 |
局限 | 抽象类有单继承的局限 | 接口没有此局限 |
选择 | 如果抽象类和接口都能使用的话,优先使用接口,因为可以避免单继承的局限 |