Java 接口
接口是面向对象的重要概念,在这篇教程会介绍 Java 接口相关内容,并看到 Java 如何使用接口来实现多态和多继承。
什么是接口
Java 中的接口也是表达了 IS-A
关系,但是接口更多的是一种行为抽象,它是对某一类的多种行为的抽象。所有实现了某个接口的类,都需要实现接口规范的行为。
如果用生活中的事物来举例的话,如果要为人定义一个接口,它通常需要规定如下的行为。
人类:每个人都要吃饭,睡觉。
根据这个人类接口的定义,我们知道人类必须包含吃饭和睡觉行为。不管你是南方人、北方人、外国人,都需要人类这个接口中所规定的吃饭和睡觉行为。虽然可能具体的行为内容不同,但是这两个行为是必须的。
为什么需要接口
可以从以下几点来考虑:
- 接口可以对行为进行完全的抽象,规范类的行为,是一种行为契约。
- 松耦合,提高代码的可读性,接口定义了一组标准的方法,使代码更易于理解和维护,但是不建议多层接口,这会增加代码的复杂性。
- 可以实现多态:接口是实现多态性的一种方式,允许不同的对象采用相同的接口进行交互,从而提高代码的可扩展性和可维护性。
- 使用接口可以实现 Java 的多继承(Java 类的继承只能单继承)。
- 提高交互的安全性:接口可以强制类必须实现某些行为或规则,保证类行为的一致性。
Java 接口定义和特点
Java 接口定义通常仅包含被 public
修饰的仅有方法定义的抽象方法,以及被 public static fianl
修饰的常量,同时使用 interface
关键词来代替 class
,接口不能被实例化。接口定义的常见方式如下:
[权限] interface interfaceName [ extends superInterfaceName ] {
// 常量
static final ...;
// 公共抽象方法的签名
...
}
具体例子:
public interface MyInterface {
String param = null;
void method1();
}
不过从 Java 8 开始,接口可以有默认方法和静态方法了,从 Java 9 开始,可以添加静态私有方法。
所以现在接口定义也可以像下面这样复杂,不过这是不建议的方式。这会增加代码的复杂性。
interface MyInterface {
String param = null; // 默认被 public static final 修饰
void method1(); // 默认被 public abstract 修饰
void method2(); // 默认被 public abstract 修饰
// 默认方法
default void defaultMethod() {
System.out.println("default method");
}
// 私有方法
private void privateMethod() {
System.out.println("private method");
}
// 静态方法
static void staticMethod() {
System.out.println("static method");
}
// 私有静态方法
private static void privateStaticMethod() {
System.out.println("private static method");
}
}
思考:为什么要在接口中增加默认方法、私有方法、静态方法、私有静态方法。
接口特点
Java 中接口的特点如下:
-
通常接口中只包含抽象方法的定义(Java 8 可以有默认方法和静态方法,Java 9 可以有私有静态方法)。
-
接口的实现类必须实现接口中所有的抽象方法。
-
接口的抽象方法默认都是被
public abstract
修饰,子类必须实现。 -
接口的属性都是被
public static final
修饰。public class JavaInterface3 { public static void main(String[] args) { System.out.println(MyInterface.param); // 输出:https://www.wdbyte.com } interface MyInterface{ String param = "https://www.wdbyte.com"; } }
-
接口不能被实例化。
-
接口可以被多个实现类实现,从而实现多态性。
interface IMobilePhone{ void mehtod1(); } class IPhone14 implements IMobilePhone{ @Override public void mehtod1() { } } class Xiaomi14 implements IMobilePhone{ @Override public void mehtod1() { } }
-
接口可以被其他接口继承,从而实现接口的扩展性。
interface MyInterface1{ void mehtod1(); } interface MyInterface2 extends MyInterface1{ void mehtod2(); }
-
接口可以用于解耦合,提高代码的可读性和可维护性。
总体来说,Java 接口是一种非常重要的语言特性,可以用于实现多态性、解耦合、提高代码可读性等。
Java 接口实现
接口既然是行为的抽象,那么就需要有具体的行为实现,类对接口的实现就是具体的行为实现。以手机为例。
定义一个手机接口,定义手机系统基本的行为。
/**
* 手机系统功能接口
*/
public interface IMobilePhoneSystem{
// 开机
void powerUp();
// 显示
void display();
// 声音
void sound();
}
单接口实现
使用 implements
关键词实现接口功能。
public class XPhone implements IMobilePhoneSystem{
@Override
public void powerUp() {
System.out.println("XPhone 开始开机");
}
@Override
public void display() {
System.out.println("XPhone 开始显示");
}
@Override
public void sound() {
System.out.println("XPhone 发出声音");
}
}
多态实现
// IMobilePhoneSystem xPhone = new XPhone();
public class XPhone implements IMobilePhoneSystem{
@Override
public void powerUp() {
System.out.println("XPhone 开始开机");
}
@Override
public void display() {
System.out.println("XPhone 开始显示");
}
@Override
public void sound() {
System.out.println("XPhone 发出声音");
}
}
// IMobilePhoneSystem miPhone = new MiPhone();
public class MiPhone implements IMobilePhoneSystem{
@Override
public void powerUp() {
System.out.println("MiPhone 开始开机");
}
@Override
public void display() {
System.out.println("MiPhone 开始显示");
}
@Override
public void sound() {
System.out.println("MiPhone 发出声音");
}
}
多接口实现
在 Java 中,一个类可以实现多个接口,以上面的例子为例,手机的功能过于原始,我们需要增加新的接口。
/**
* 手机基本功能
*/
public interface IMobilePhoneBasicFunction {
// 打电话
void call();
// 发短信
void sendMessage();
}
修改 XPhone
实现多个接口,XPhone
必须实现两个接口中的所有抽象方法。
public class XPhone implements IMobilePhoneSystem,IMobilePhoneBasicFunction{
@Override
public void powerUp() {
System.out.println("XPhone 开始开机");
}
@Override
public void display() {
System.out.println("XPhone 开始显示");
}
@Override
public void sound() {
System.out.println("XPhone 发出声音");
}
@Override
public void call() {
System.out.println("XPhone 开始拨打电话");
}
@Override
public void sendMessage() {
System.out.println("XPhone 开始发送短信");
}
}
此时,XPhone
的继承关系如下。
可以对 XPhone
进行测试:
XPhone xPhone = new XPhone();
xPhone.powerUp(); // XPhone 开始开机
xPhone.call(); // XPhone 开始拨打电话
接口继承接口
再次分析上面的两个接口,可以发现,IMobilePhoneBasicFunction
接口和 IMobilePhoneSystem
不应该是相等的关系,IMobilePhoneSystem
应该作为手机功能的基础。因此 IMobilePhoneBasicFunction
需要继承 IMobilePhoneSystem
的所有行为抽象。
代码实现:
/**
* 手机基本功能
*/
public interface IMobilePhoneBasicFunction extends IMobilePhoneSystem {
// 打电话
void call();
// 发短信
void sendMessage();
}
public class XPhone implements IMobilePhoneBasicFunction{
//....
}
使用 extends
这种简单的方式可以对接口进行继承。
空接口
空接口,顾名思义,没有任何行为限制的接口,如:
public interface IMobilePhone{
}
这样的接口也有它的作用,可以理解为对某一些类打了个标记,后续的某些操作可以以判断是否实现了某个接口为依据。比如常见的两个空接口 Serializable
和 Cloneable
.
-
Serializable
:用于标记类可以被序列化。 -
Cloneable
:用于标记类可以被克隆。
Java 接口实现特点
- 一个类可以实现多个接口。
- 接口可以继承接口。
接口和类和抽象类区别
接口和抽象类的区别。
区别 | 接口 | 抽象类 |
---|---|---|
继承 | 使用 implements 关键字实现 |
使用 extends 关键字实现 |
定义 | 通常定义了一组规范,规范要具体的行为 | 定义了一些抽象方法,但也可以包含具体方法 |
方法 | 通常方法都是抽象的,不能有具体实现,(静态方法、默认方法比较特殊)。 | 可以定义抽象方法,也可以包含具体方法 |
实现 | 接口不能实例化,接口可以被类实现 | 不能被实例化,只能被类继承 |
多继承 | 类可以实现多个接口 | 类只能继承一个抽象类 |
特点 | 用于解耦程序,提高代码的复用性和灵活性 | 用于提供一些通用的行为和属性,可以被具体类继承和扩展 |
接口和类的区别。
区别 | 接口 | 类 |
---|---|---|
定义 | 通常只定义了一些行为规范 | 定义了一些属性和方法,可以包含具体行为实现 |
多继承 | 可以实现多个接口 | 只能继承一个类 |
实例化 | 不能被实例化,只能被类实现 | 可以被实例化,创建多个对象 |
一如既往,文章中代码存放在 Github.com/niumoo/javaNotes.