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不支持多继承,所以可以通过实现多个接口来达到类似的目的。
      • 当希望强制要求一些类实现一组特定的方法时,可以定义一个接口让这些类去实现。

接口的应用

  • 除了实例化实现接口的类以外
  • 还可以在普通类中先声明接口,在设计构造函数强制传入实现接口的类的对象,在普通类示例化的时候,普通类实例化对象,接口的声明即会更具情况持有不同的接口实现类的对象(多态),在使用接口的引用去调用方法,具体用法请看查看泛型在接口的应用
相关推荐
召田最帅boy2 小时前
SpringBoot实现AI智能评论审核与自动回复
人工智能·spring boot·后端·架构
江湖十年2 小时前
使用 testing/synctest 测试并发代码
后端·面试·go
苦瓜小生2 小时前
【黑马点评学习笔记 | 实战篇 】| 7-达人探店
redis·笔记·后端·学习
常利兵2 小时前
Spring Boot缓存新玩法:一键切换,租户无忧
spring boot·后端·缓存
想你的液宝2 小时前
Spring Boot @RestControllerAdvice:统一异常处理的利器
后端
大傻^2 小时前
Spring AI Alibaba 企业级实战:从0到1构建智能客服系统
java·人工智能·后端·spring·springaialibaba
短剑重铸之日2 小时前
《ShardingSphere解读》11 解析引擎:SQL 解析流程应该包括哪些核心阶段?(上)
java·后端·spring·shardingsphere·分库分表
MekoLi292 小时前
MongoDB 新手完全指南:从入门到精通的实战手册
数据库·后端
会算数的⑨2 小时前
演进——从查日志到 AI 自治,企业监控体系的变迁
人工智能·分布式·后端·微服务·云原生