Java面向对象之接口(interface)

接口

  • java中还有一种特殊的抽象类叫做接口

引入

  • java有一种特殊的抽象类叫做接口,我们可以创建一个接口用来管理子类,使用子类实现该接口,如下方代码所示创建一个Animal接口:

  • 在接口中方法要为抽象方法,否则会报错,除非版本大于java8.0,可以用default和static修饰的方法

    • 在接口中只能使用public abstract来声明方法,而且因为只有一种写法public和abstract是可以省略的
    • 接口自带public static final修饰变量,自带public abstract 修饰方法
    • 接口可以继承其他接口 ,且为多继承(弥补了在java中类不能多继承的功能缺失)
    • 接口类中的静态方法和普通的类不同,静态方法不但在物理空间上始终属于接口,且只能通过接口类名访问,这是为了避免接口多继承导致的钻石继承问题
    java 复制代码
    package com.inter;
    
    //public class Animal {
    public interface  Animal { //使用interface关键字替代class创建接口
        //因为在接口中会将方法默认指定为public和abstract,哪怕不写也是一样的
    //    private void sleep();//接口中只允许将对象设置为public
        void sleep();
    //    int a = 1;
        //实际上在接口中的成员变量默认为
        public static final int a = 1;//但实际上也可以只写为int a = 1;省略public static final
        //因为变量被final修饰过所以必须要对变量进行初始化,因为用了static修饰,所以在AnimalTest的mian方法中可以直接使Aanmal.a拿到Animal类中的a的值
    
        void eat();
        //在java8之后接口内也可以定义普通方法,使用default修饰符或者Static修饰符就行
        default void game(){
            test();
            System.out.println("狗子在玩");
        }
        static void run(){
            System.out.println("狗子在跑");
        }
        //    java9之后使用private也是被允许的
        private void test(){
            System.out.println("测试private");
        } //因为使用private进行修饰,所以只能在接口Animal类中调用
    }
  • 使用Dog类和Cat类来实现接口,这里我们使用关键字 implements+接口名 来表示该类是用于实现哪个接口的 ,实际上,实现接口也是一种特殊的继承

java 复制代码
// Dog  
package com.inter;

public class Dog implements Animal{  
    @Override  
    public void sleep() {  
        System.out.println("狗子在睡觉");  
    }//当实现接口的类是空的时候,光标留在类名处按下键盘的"alt + enter" ,ide会帮我们弹出对话框,里面有要实现的抽象方法

    @Override  
    public void eat() {  
        System.out.println("狗子吃骨头");  
    }  

}
  • AnimalTest类作为测试用例:
java 复制代码
package com.inter;

public class AnimalTest {  
    public static void main(String[] args){  
        int a = Animal.a;//不用创建对象就可以访问成员变量a  
        // Animal animal = new Animal();
        //不能创建对象,因为Animal为接口,接口的本质为抽象类,而抽象类是不能被实例化的  
        //想要使用接口就必须用类来实现它,下面我们创建一个Dog类来实现接口  
        Dog dog = new Dog();  
        dog.eat();  
        dog.sleep();  
        //要使用接口中的普通方法,只能通过类名,或者说是接口名进行访  
        dog.game(); //implements实现接口就相当于继承了接口的内容 
        // dog.run();//发现访问失败,虽然dog相当于Animal的子类但run使用的static修饰的
        Animal.run();  
    }  
}

接口的继承

  • 接口也是可以继承的,创建一个Atest类,继承自Animal
java 复制代码
package com.inter;  
  
public interface Atest extends Animal{  
    //接口的继承例子  
    void OnTest();  
    void Onclick();  
}
  • 写一个Atest的测试用例类,AtestGet.java,我们发现java会强制我们实现接口Atest和其继承的接口Animal,如下方代码所示:
java 复制代码
package com.inter;  
  
public class AtestGet implements Atest{  
    @Override  
    public void OnTest() {  
  
    }  
  
    @Override  
    public void Onclick() {  
  
    }  
  
    @Override  
    public void sleep() {  
  
    }  
  
    //继承于Animal接口的实现的抽象方法  
    @Override  
    public void eat() {  
  
    }  
  
    @Override  
    public void game() {  
        Atest.super.game();  
    }  
}

接口的多继承

  • 虽然java是单继承语言,但是java的接口是可以多继承的,比如这里我简单写两个接口,注意这两个接口中我使用了同名的方法,在Java8之后为了方便实现的类选择具体实现哪个接口的方法,需要使用default参数修饰接口中同名的方法
java 复制代码
//接口A
public interface InterfaceA {
    default void commonMethod() {
        System.out.println("InterfaceA 的 commonMethod");
    }
}
//接口B
public interface InterfaceB {
    default void commonMethod() {
        System.out.println("InterfaceB 的 commonMethod");
    }
}
  • 一个类可以实现多个接口,当接口类中方法的名字冲突时,使用interFaceName.super.functionName()来选择具体是哪个接口的方法:
java 复制代码
public class MyClass implements InterfaceA, InterfaceB {
    @Override
    public void commonMethod() {
        // 选择调用 InterfaceA 的默认方法
        InterfaceA.super.commonMethod();
        // 添加自己的具体实现
        System.out.println("Test");
    }
    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        myClass.commonMethod();
    }
}

运行输出示例:

复制代码
InterfaceA 的 commonMethod
Test
  • 当然如果多继承的接口中有同名的抽象方法,当原型相同时,只需要实现一个抽象方法
java 复制代码
public interface InterfaceA {
    void commonMethod();
}

public interface InterfaceB {
    void commonMethod();
}
public class MyClass implements InterfaceA, InterfaceB {
    @Override
    public void commonMethod() {
        // 只需要实现一次!
        System.out.println("同时满足两个接口的要求");
    }
}
  • 当然如果多继承的接口中有同名的抽象方法,当原型不相同时,要在实现类中重载实现抽象方法:
java 复制代码
public interface InterfaceA {
    void commonMethod(String s);  // 参数是 String
}

public interface InterfaceB {
    void commonMethod(int i);     // 参数是 int
}

public class MyClass implements InterfaceA, InterfaceB {
    
    @Override
    public void commonMethod(String s) {
        System.out.println("String版本: " + s);
    }
    
    @Override
    public void commonMethod(int i) {
        System.out.println("int版本: " + i);
    }
    
    public static void main(String[] args) {
        MyClass m = new MyClass();
        m.commonMethod("hello");  // 调用 String 版本
        m.commonMethod(100);      // 调用 int 版本
    }
}

总结

  • 虽然在ide中接口文件是没有后缀的,但是打开资源管理器查看可以发现其实接口还是java文件

  • 接口实际上相当于特殊的抽象类,所以不能实例化

  • 在接口中只能使用public abstract来声明方法,而且因为只有一种写法所以public abstract是可以省略的,只要在抽象类中创建方法默认就是public abstract

  • 接口自带public static final修饰变量,自带public abstract 修饰方法

  • 在接口中方法要为抽象方法,否则会报错,除非版本大于java8.0,才可以用default和static修饰的方法

  • 在实现类中使用implements interName实现接口,实际上这也是一种特殊的继承

  • 接口可以继承其他接口

    • 接口支持多继承,一般的抽象方法,如果重名会同时实现一套方法,在java8之后提供了default修饰的方法,在是现时可以选择要实现哪个接口中的同名方法,通过interFaceName.super.functionName()
  • 接口不能实现其他接口

  • 当类实现接口时,如果有抽象方法没有被实现,ide会报错提示我们实现该方法,我们只需要按下alt+enter就可以在实现接口的类中写入该方法的方法体:

接口与抽象类对比

联系

  • 抽象化: 无论是抽象类还是接口,都可以包含抽象方法,即没有方法体的方法。这些方法需要在子类或实现类中具体实现。
  • 多态: 通过抽象类或接口,可以实现多态性,允许父类引用变量持有子类对象,从而实现方法的动态绑定。
  • 封装:它们都可以帮助实现良好的封装,隐藏对象的具体实现细节,只暴露公共接口给外部使用。

不同

  • 定义方式

    • 抽象类使用abstract class关键字定义
    • 接口使用interface关键字定义。
  • 继承方式

    • 由于java是单继承语言,一个类只能继承一个抽象类,但可以实现多个接口。

    • 抽象类可以有构造器,而接口不能有构造器。

    • 抽象类中可以有实例变量,而接口中所有的属性默认都是public static final,即常量

      • 这里要注意的是虽然抽象类没有办法被实例化,但是其变量是可以被子类继承的,而默认变量(public static final)则都是静态变量,属于接口类,不能被子类(实现接口的类)继承,只能是通过子类对象访问。
    • 总的来说,抽象类可以给子类可继承的普通变量和方法,而接口则不行

  • 方法实现

    • 抽象类可以包含非抽象方法(即已经实现了的方法),也可以包含抽象方法。
    • 接口中所有方法默认都是publicabstract的,从Java 8开始,接口还可以包含默认方法(default)和静态方法(static),这使得接口中的方法可以有具体的实现。
  • 使用场景

    • 抽象类:

      • 当几个相关的类共享了相同的代码时,可以将这些共有的部分提取到一个抽象类中。
      • 当想要保护某些方法不被子类重写 时,可以在抽象类中定义这些方法为final
    • 接口

      • 当需要定义一个类型,该类型具有特定的行为但不关心实现细节时,可以使用接口。
      • 当需要实现多重继承的效果时,由于Java不支持多继承,所以可以通过实现多个接口来达到类似的目的。
      • 当希望强制要求一些类实现一组特定的方法时,可以定义一个接口让这些类去实现。

接口的应用

  • 除了实例化实现接口的类以外
  • 还可以在普通类中先声明接口,在设计构造函数强制传入实现接口的类的对象,在普通类示例化的时候,普通类实例化对象,接口的声明即会更具情况持有不同的接口实现类的对象(多态),在使用接口的引用去调用方法,具体用法请看查看泛型在接口的应用
相关推荐
程序员cxuan13 小时前
速度太快了!本地可以跑 DeepSeek-V4-Flash 了
人工智能·后端·程序员
阿祖zu14 小时前
芝士就是力量!开源私有化部署与 GitHub 双向同步的个人知识笔记 App
前端·后端·ios
不才不才不不才14 小时前
Spring 源码系列(16): doDispatch 全流程——一次请求的主干链路
java·后端·spring
IT_陈寒14 小时前
SpringBoot自动配置失效?这个隐藏配置坑了我一整晚
前端·人工智能·后端
搜狐技术产品小编202314 小时前
告别“黑盒”与误判:如何用“多智能体对抗辩论”重构内容安全审核系统
后端·多agent
DantyWei15 小时前
controller注册及调用时机
后端
edwarddamon15 小时前
Spring Cloud 配置热更新与 Bean 代理机制梳理
java·后端
码事漫谈15 小时前
我用 Seed Evolving 做了个 AI 小说写作工具
后端
Raas10015 小时前
MAIGateway,魔芋企业级AI网关的FinAPI成本竞争力设计
java·后端·网关·api网关·魔芋ai·finapi·mai gateway
计算机魔术师16 小时前
传统基础架构 - 微服务
大数据·后端·微服务·架构·开发工具·编程语言