目录
3.接口中每一个方法都是public的抽象方法, 即接口中的方法会被隐式的指定为 public abstract
7. 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class
8. 如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类
9. jdk8之后:接口中还可以包含default方法和static方法,可以进行具体实现
10.接口也可以发生向上转型,也可以发生动态绑定,也可以发生多态
一、引言
什么是接口?
在 Java 中,接口(Interface)是一种抽象类型,它定义了一组方法和常量,但不提供任何具体的实现。接口充当一种契约的角色,规定了类必须遵守的协议。任何实现了接口的类都必须实现接口中定义的所有方法。
接口与 Java 编程中的角色和重要性
接口在 Java 编程中扮演着至关重要的角色。它们支持多重继承的概念,允许一个类实现多个接口。这种设计模式鼓励代码的模块化和可重用性,并提高了代码的可维护性和可扩展性。此外,接口还被广泛用于定义通用的编程规范,使不同的类能够以统一的方式进行交互。
二、Java 接口基础及其特性
定义接口的语法
在 Java 中,使用 interface
关键字定义接口。
接口的定义格式与定义类的格式基本相同,将class关键字换成 interface 关键字,就定义了一个接口。
接口定义的语法如下:
[可见性] interface 接口名称 [extends 其他接口名] {
// 常量定义
// 方法声明
}
1.接口中的方法(抽象方法的概念)
接口中定义的方法都是隐式抽象的,也就是说,它们没有方法体。这些方法必须由实现该接口的类来提供具体的实现。例如:
public interface Walkable {
void walk(); // 抽象方法,没有方法体
}
2。接口中的默认方法和静态方法
从 Java 8 开始,接口可以定义默认方法和静态方法。默认方法提供了一个默认的实现,可以被实现该接口的类继承或重写。静态方法则可以在接口内部直接调用,无需实例化接口。
interface Walkable {
void walk(); // 抽象方法
default void run() { // 默认方法
System.out.println("Running...");
}
static void printInfo() { // 静态方法
System.out.println("This is the Walkable interface.");
}
}
3.接口中每一个方法都是public的抽象方法, 即接口中的方法会被隐式的指定为 public abstract
(只能是 public abstract,其他修饰符都会报错,如protected abstract和private abstract )
与第九点进行区分(jdk8之后有扩展)
4.重写接口中方法时,不能使用默认的访问权限
5接口中的常量
接口中定义的变量都是隐式的 public static final
类型(当然你也可显示的写出来,只不过编译器会告诉你那是多余的),也就是常量。常量的值必须在定义时指定,后续不能修改。
interface Constants {
int MAX_VALUE = 100; // 常量
String MESSAGE = "Hello, World!";
}
6.接口类型是一种引用类型,但是不能直接new接口的对象
7. 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class
8. 如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类
9. jdk8之后:接口中还可以包含default方法和static方法,可以进行具体实现
public interface duck {
void eat();
default void run(){
//具体实现
};
static void fly(){
//具体实现
};
}
ps:
1.(private方法在IDE上不会报错,但是被private修饰了,其他类就没有能力使用那个类,等于形同虚设,所以不要用private)。
2.接口中不可以有默认方法,即public/protected void run(){}
10.接口也可以发生向上转型,也可以发生动态绑定,也可以发生多态
ps:接口这样设计有什么好处呢?
时刻牢记多态的好处, 让程序猿忘记类型. 有了接口之后, 类的使用者就不必关注具体类型,
三、实现接口
如何实现一个接口(包括一个或多个接口)
要实现一个接口,类必须使用 implements
关键字,并提供接口中所有抽象方法的具体实现。一个类可以同时实现多个接口,只需用逗号分隔接口名即可。
class MyClass implements Interface1, Interface2 {
// 实现 Interface1 中的方法
// 实现 Interface2 中的方法
}
接口与继承类的区别和联系
- 继承是一种"是一个"的关系,子类继承了父类的所有属性和方法。而实现接口是一种"能-做"的关系,类实现了接口中定义的协议。
- 子类和父类之间是extends 继承关系,类与接口之间是 implements 实现关系。
- 一个类只能继承一个父类,但可以实现多个接口。
- 接口只定义了方法的签名,实现由实现类提供。而抽象类可以包含具体的方法实现。
示例:
创建接口并实现它的具体类
让我们创建一个 Flyable
接口,并实现一个 Bird
类:
// 定义接口
interface Flyable {
void fly();
void landing();
}
// 实现接口
class Bird implements Flyable {
@Override
public void fly() {
System.out.println("The bird is flying!");
}
@Override
public void landing() {
System.out.println("The bird is landing.");
}
public static void main(String[] args) {
Bird bird = new Bird();
bird.fly();
bird.landing();
}
}
四、接口的实际应用
接口作为 API 的契约
接口在定义 API 时扮演着重要角色。它们定义了一组方法,作为与外部系统交互的契约。任何实现该接口的类都必须遵守这个契约,从而确保API的一致性和可靠性。
使用接口提高模块化和可替换性
接口支持模块化设计,将系统划分为独立的模块,每个模块实现一个或多个接口。这种设计方式增强了代码的可维护性和可扩展性。此外,接口还提高了代码的可替换性,因为只要实现相同的接口,一个模块就可以被另一个模块替换。
设计模式中的接口应用
接口在多种设计模式中发挥着关键作用,例如:
- 适配器模式: 使用接口将不兼容的类包装起来,提供统一的接口。
- 工厂模式: 工厂类返回实现特定接口的对象实例。
- 观察者模式: 观察者和被观察者之间通过接口进行通信。
1. 适配器模式(Adapter Pattern)
适配器模式用于将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以一起工作。
假设我们有一个LightningPhone
接口,它有一个recharge
和useLightning
方法,我们还有一个MicroUsbPhone
接口,它有一个recharge
和useMicroUsb
方法。我们需要一个适配器使得MicroUsbPhone
可以通过LightningPhone
接口使用。
接口定义:
interface LightningPhone {
void recharge();
void useLightning();
}
interface MicroUsbPhone {
void recharge();
void useMicroUsb();
}
适配器实现:
// 适配器实现 LightningPhone 接口
class LightningToMicroUsbAdapter implements LightningPhone {
private MicroUsbPhone microUsbPhone;
public LightningToMicroUsbAdapter(MicroUsbPhone phone) {
this.microUsbPhone = phone;
}
@Override
public void recharge() {
microUsbPhone.recharge();
}
@Override
public void useLightning() {
microUsbPhone.useMicroUsb();
System.out.println("Lightning connected via Micro USB.");
}
}
2. 工厂模式(Factory Pattern)
工厂模式用于创建对象,允许接口指定对象的类型,但由子类决定实例化哪一个类。这样,工厂方法在类的实例化过程中扮演了“工厂”的角色。
假设我们有一个Phone
接口和两个实现了Phone
接口的类:AndroidPhone
和IPhone
。
接口定义:
interface Phone {
void makeCall();
void sendSMS();
}
class AndroidPhone implements Phone {
public void makeCall() {
System.out.println("Android call");
}
public void sendSMS() {
System.out.println("Android SMS");
}
}
class IPhone implements Phone {
public void makeCall() {
System.out.println("iPhone call");
}
public void sendSMS() {
System.out.println("iPhone SMS");
}
}
工厂类实现:
class PhoneFactory {
public Phone getPhone(String type) {
if (type.equalsIgnoreCase("iPhone")) {
return new IPhone();
} else if (type.equalsIgnoreCase("Android")) {
return new AndroidPhone();
}
return null;
}
}
3.观察者模式(Observer Pattern)
观察者模式用于建立一种对象与对象之间的依赖关系,一个对象改变状态时,所有依赖于它的对象都会得到通知并被自动更新。
接口定义:
interface Observer {
void update(String message);
}
interface Subject {
void attach(Observer o);
void detach(Observer o);
void notifyUpdate(String message);
}
模式实现:
class NewsAgency implements Subject {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer o) {
observers.add(o);
}
public void detach(Observer o) {
observers.remove(o);
}
public void notifyUpdate(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
class NewsChannel implements Observer {
private String news;
@Override
public void update(String news) {
this.news = news;
System.out.println("NewsChannel updated: " + news);
}
}
五、接口与抽象类的区别
class Animal{
protected String name;
public Animal (String name){
this.name = name;
}
}
此处的 Animal 中包含一个 name 这样的属性, 这个属性在任何子类中都是存在的. 因此此
感谢您耐心阅读这篇关于Java接口的文章!如果这些内容对您有所启发,或者您有更多的见解和疑问,欢迎在下方评论区留言分享您的想法。交流和讨论可以帮助我们共同进步!
如果您喜欢这篇文章,请不要吝啬您的点赞👍,您的每一个赞都是对我写作的最大鼓励。同时,您可以收藏🌟这篇博客,方便日后查阅或与朋友分享。
再次感谢您的阅读与支持!期待在评论区与您的精彩互动!💬