当前位置: 首页 > news >正文

【JAVASE】-9- 接口语法基础

一、上节回顾 

 1. 向上转型(子 → 父 类型转换)

向上转型是 “子类对象赋值给父类引用” 的过程,是多态的基础,图中总结了 3 种常见时机:

1. 直接赋值
Animal animal = new Dog("圆圆", 19);

  • 解释:Dog 是 Animal 的子类,直接将 Dog 实例赋值给 Animal 类型的引用 animal,自动完成向上转型。

2. 方法传参时转型
public static void func1(Animal animal) { /* ... */ }public static void main(String[] args) {Dog dog = new Dog("圆圆", 19);func1(dog); // 传参时,dog(Dog类型)自动向上转型为Animal类型
}

  • 解释:调用 func1 时,实际参数是 Dog 类型,但方法形参要求 Animal 类型,因此自动发生向上转型。

3. 返回值转型
public static Animal func2() {Dog dog = new Dog("圆圆", 19);return dog; // 返回时,dog(Dog类型)自动向上转型为Animal类型
}

  • 解释:方法声明返回 Animal 类型,但实际返回 Dog 类型,因此自动发生向上转型。

2. 方法重写(Override)

子类对父类的非静态、非 private、非 final方法进行 “同名、同参数列表、兼容返回值” 的实现,是多态的核心表现。

  • 方法名相同;
  • 参数列表(参数个数、类型、顺序)相同;
  • 返回值相同(或子类返回值是父类返回值的 “协变类型”,如父类返回 Animal,子类可返回 Dog);
  • 访问修饰符:子类方法的访问范围 ≥ 父类方法(如父类是 protected,子类可改为 public);
  • 限制:privatestaticfinal 修饰的方法不能被重写,构造方法也不能被重写。
@Override
public void eat() {System.out.println(this.name + " 正在吃狗粮!");
}

  • 作用:编译期校验 “是否真的重写了父类方法”。如果方法签名与父类不匹配(如方法名写错、参数不对),编译器会报错,避免逻辑错误。

 

3. 动态绑定(运行时多态)

Java 中,对象的方法调用是 “运行时绑定”—— 即调用哪个类的方法,由运行时对象的实际类型决定,而非编译时的引用类型。

Animal animal = new Dog("圆圆", 19);
animal.eat();

  • 编译时:编译器看到 animal 是 Animal 类型,因此会检查 Animal 类中是否有 eat() 方法(有则编译通过)。
  • 运行时:animal 实际指向 Dog 实例,因此 JVM 会调用 Dog 类的 eat() 方法(即使编译时检查的是 Animal 的方法)。

字节码层面(第三张图黑色部分):

  • invokevirtual #5 // Method Animal.eat:()V:编译时生成的是调用 Animal.eat() 的字节码,但运行时 JVM 会根据对象实际类型(Dog),动态找到并调用 Dog.eat()

4. 协变返回类型(拓展知识)

    子类重写方法时,返回值可以是父类方法返回值的子类类型,称为 “协变返回”。

    class Animal {public Animal eat() { return this; }
    }class Dog extends Animal {@Overridepublic Dog eat() { return this; } // 合法:Dog是Animal的子类
    }
    

    • 作用:让方法重写更灵活,子类可返回更具体的类型。

    二、接口引入 

    • USB接口,定义 USB 设备的通用方法(openDevice()closeDevice())。
    • Mouse实现 USB 接口的类,代表 “鼠标”,额外有 click() 方法。
    • KeyBoard实现 USB 接口的类,代表 “键盘”,额外有 input() 方法。
    • Computer电脑类,通过 useService(USB usb) 方法使用 USB 设备。

    1. Computer 类的方法
    // 关闭电脑的方法
    public void powerOff() {System.out.println("关闭电脑!");
    }// 电脑使用 USB 设备的核心方法
    public void useService(USB usb) {usb.openDevice(); // 调用 USB 设备的“打开”方法(多态:实际调用子类重写的方法)// 向下转型:判断 usb 实际类型,转为子类并调用特有方法if (usb instanceof Mouse) {Mouse mouse = (Mouse) usb; // 向下转型为 Mousemouse.click(); // 调用 Mouse 特有的“点击”方法} else if (usb instanceof KeyBoard) {KeyBoard keyBoard = (KeyBoard) usb; // 向下转型为 KeyBoardkeyBoard.input(); // 调用 KeyBoard 特有的“输入”方法}usb.closeDevice(); // 调用 USB 设备的“关闭”方法(多态)
    }
    

    2. Test 类的 main 方法
    public class Test {public static void main(String[] args) {// 1. 创建电脑对象Computer computer = new Computer();computer.powerOn(); // 假设存在 powerOn 方法(代码中未展示,逻辑上是“开机”)// 2. 创建鼠标、键盘对象Mouse mouse = new Mouse();KeyBoard keyBoard = new KeyBoard();// 3. 电脑使用鼠标(向上转型)computer.useService(mouse); // mouse(Mouse 类型)自动向上转型为 USB 类型System.out.println("==========");// 4. 电脑使用键盘(向上转型)computer.useService(keyBoard); // keyBoard(KeyBoard 类型)自动向上转型为 USB 类型// 5. 关闭电脑computer.powerOff();}
    }
    

    1. 向上转型(Upcasting)

    • 发生场景:调用 computer.useService(mouse) 和 computer.useService(keyBoard) 时。也就是Usb usb=new Mouse(),后者是mouse,mouse向上转型为Usb类型
    • 解释:Mouse 和 KeyBoard 都实现了 USB 接口,因此它们的实例可以自动转换为 USB 类型(父接口引用指向子实现对象)。
    • 作用:让 Computer 类无需关心 “具体是鼠标还是键盘”,只需通过 USB 接口调用通用方法(openDevice()closeDevice()),体现了多态的 “抽象依赖”

    2. 向下转型(Downcasting)

    • 发生场景:useService 方法中 (Mouse) usb 和 (KeyBoard) usb
    • 解释:将 USB 类型的引用强制转换为具体子类类型Mouse 或 KeyBoard),从而调用子类的特有方法(如 mouse.click()keyBoard.input())。
    • 前提:必须先用 instanceof 判断 usb 的实际类型,否则运行时可能抛出 ClassCastException(类型转换异常)。

    3. 多态(Polymorphism)

    • 体现:usb.openDevice() 和 usb.closeDevice() 方法。这是接口的抽象方法,子类通过继承来实现特定的该方法,多态。
      • 编译时,usb 是 USB 类型,因此编译器检查 USB 接口是否有 openDevice()/closeDevice() 方法。
      • 运行时,usb 实际是 Mouse 或 KeyBoard 实例,因此会调用子类重写的 openDevice()/closeDevice() 方法这叫动态绑定。

    三、接口 

    1. 接口的定义形式

    接口是一种引用数据类型,使用 interface 关键字定义,例如:

    interface USB {// 接口内容
    }
    

    2. 接口中的方法规则

    接口中默认只有抽象方法(没有方法体的方法),但有两个例外:

    • static 修饰的方法:属于接口的 “静态方法”,有方法体,通过接口名直接调用(如 USB.show())。
    • default 修饰的方法:属于接口的 “默认方法”,有方法体,实现类可以直接继承或重写。

    static不能重写,抽象方法必须重写,default可重写也可以不重写

    此外,接口中普通的抽象方法默认会被 public abstract 修饰(即使不写,编译器也会自动添加)。

    3. 接口中的成员变量规则

    接口中的成员变量,默认会被 public static final 修饰(即 “公共的、静态的、最终的” 常量):

    • public:全局可见。
    • static:属于接口本身,可通过接口名直接访问(如 USB.VERSION)。
    • final:值不可修改(常量)。
    interface USB {String VERSION = "3.0"; // 等价于 public static final String VERSION = "3.0";
    }
    

    4. 接口不能实例化

    接口是 “行为规范”,不是具体的类,因此不能直接创建接口的对象(如 new USB() 会报错)。

    要使用接口,必须通过 ** 实现类(implements 接口的类)** 创建对象,再通过接口引用指向实现类对象(多态)。

    5. 类与接口的关系

    类和接口之间是 **“实现(implements)” 关系 **,一个类可以实现多个接口(Java 支持 “多接口实现”,弥补了单继承的不足)。

    class Mouse implements USB, Wireless { // Mouse 类实现了 USB 和 Wireless 两个接口// 实现接口的抽象方法@Overridepublic void openDevice() {System.out.println("鼠标打开");}// ...
    }
    

    6. 接口的字节码文件

    接口编译后,会生成独立的 .class 字节码文件(与类的字节码类似),JVM 会像加载类一样加载接口的字节码。

    四、接口和类的关系 

    1. “接口也属于一种类型”

    在 Java 中,类型分为基本数据类型(如 intchar 等)和引用数据类型(如类、接口、数组等)。接口属于引用数据类型,它和类一样,能用于声明变量、作为方法参数或返回值类型等。例如,我们可以声明一个接口类型的变量:

    // USB 是一个接口
    USB usb;
    

    2. “接口可以去引用 实现了该接口的具体的类型”

    如果有一个类 Mouse 实现了 USB 接口(使用 implements 关键字),那么我们可以用 USB 类型的变量来引用 Mouse 类的对象,这就是多态的一种表现形式。示例如下:

    interface USB {void open();void close();
    }class Mouse implements USB {@Overridepublic void open() {System.out.println("鼠标开启");}@Overridepublic void close() {System.out.println("鼠标关闭");}// 鼠标特有的方法public void click() {System.out.println("鼠标点击");}
    }public class Test {public static void main(String[] args) {// 接口类型的变量 usb 引用了实现类 Mouse 的对象USB usb = new Mouse();// 调用接口中定义的方法,实际执行的是 Mouse 类中重写的方法usb.open();usb.close();// 注意:此时 usb 不能直接调用 Mouse 类特有的 click 方法,// 如果要调用,需要进行向下转型if (usb instanceof Mouse) {Mouse mouse = (Mouse) usb;mouse.click();}}
    }
    

    在这个例子中,USB 是接口,Mouse 是实现了 USB 接口的具体类。我们创建了 Mouse 类的对象,并把它赋值给 USB 类型的变量 usb,这就是 “接口引用实现了该接口的具体类的对象”。通过这种方式,我们可以在不关心具体实现类的情况下,通过接口来调用方法,体现了面向接口编程的思想,也让代码更加灵活、可扩展。

    五、接口如何解决 Java 的 “多继承限制” 

    子类是父类(继承),具有什么功能(接口)

    1. Java 的 “单继承限制”

    Java 中,一个类只能直接继承一个父类(即 “单继承”)。如果我们想让一个类同时拥有 “飞行”“奔跑”“游泳” 等多种行为,仅靠类的继承无法实现 —— 因为不能同时继承多个包含这些行为的父类。

    2. 直接在父类中写通用行为的问题

    假设我们有抽象父类 Animal,如果把 fly()run()swim() 直接写在 Animal 中:

    abstract class Animal {// ... 其他成员public void fly() {}   // 飞行行为public void run() {}   // 奔跑行为public void swim() {}  // 游泳行为
    }
    

    这会产生问题:不是所有动物都具备这些行为(比如蛇不会飞,鱼不会跑)。如果子类继承 Animal,会被迫继承所有不需要的行为,违背 “设计的合理性”。

    3. 接口的 “多实现” 解决思路

    为了让类能灵活组合不同的行为,我们可以把 “飞行”“奔跑”“游泳” 这些行为抽象为独立的接口

    interface IFly {void fly();
    }interface IRun {void run();
    }interface ISwim {void swim();
    }
    

    然后,类可以同时实现多个接口,从而 “选择性地拥有所需行为”:

    // 例如:鸟类(会飞、会跑)
    class Bird extends Animal implements IFly, IRun {@Overridepublic void fly() { System.out.println("鸟飞行"); }@Overridepublic void run() { System.out.println("鸟奔跑"); }
    }// 例如:鱼类(会游泳)
    class Fish extends Animal implements ISwim {@Overridepublic void swim() { System.out.println("鱼游泳"); }
    }
    

    4. 接口解决 “多继承” 的本质

    • Java 类单继承:保证类的继承关系简单,避免 “钻石继承” 等复杂问题。
    • Java 类多实现接口:突破了单继承的限制,让类可以同时拥有多个接口的 “行为能力”,实现了 “多行为的组合”。

    这种设计既保留了单继承的简洁性,又通过接口的多实现,满足了 “一个类需要多种不同行为” 的需求,因此说接口解决了 Java 的多继承问题(更准确地说,是 “补充了单继承的不足,实现了类似多继承的‘多行为组合’效果”)。

    ⭐ 总结

    接口通过 “多实现” 的特性,让 Java 类能在不违反 “单继承” 规则的前提下,灵活组合多种行为,从而弥补了单继承无法实现 “多行为复用” 的缺陷,间接解决了 “多继承” 场景下的需求。

    六、接口继承接口,类实现接口 

    1. 接口的继承关系

    • 接口 A 声明了抽象方法 testA()
    • 接口 B 通过 extends A 继承了接口 A,因此 B 不仅有自己的 testB() 方法,还 “继承” 了 A 的 testA() 方法。
    • 此时,接口 B 包含两个抽象方法:testA()(来自 A)和 testB()(自己声明)。

    2. 实现类的要求

    类 TestDemo1 实现了接口 B(使用 implements B),因此必须重写 B 中所有的抽象方法,包括:

    • testA():继承自接口 A 的方法。
    • testB():接口 B 自身声明的方法。

    3. 代码逻辑演示

    interface A {void testA();
    }interface B extends A {void testB();
    }class TestDemo1 implements B {@Overridepublic void testA() {System.out.println("实现 testA 方法");}@Overridepublic void testB() {System.out.println("实现 testB 方法");}
    }public class Main {public static void main(String[] args) {TestDemo1 demo = new TestDemo1();demo.testA(); // 输出:实现 testA 方法demo.testB(); // 输出:实现 testB 方法}
    }
    

    七、接口 + 抽象类的优势 

    通过抽象类封装 “共有属性 / 基础行为”接口封装 “特有行为”,可以完美解决上述问题:

    // 抽象父类:封装动物的共有属性(如名字、年龄)和基础行为
    abstract class Animal {protected String name;protected int age;public Animal(String name, int age) {this.name = name;this.age = age;}// 所有动物都需要“吃”,定义为抽象方法,由子类实现public abstract void eat();
    }// 接口:封装“飞行”行为
    interface IFly {void fly();
    }// 接口:封装“奔跑”行为
    interface IRun {void run();
    }// 接口:封装“游泳”行为
    interface ISwim {void swim();
    }// 子类:鸟(会飞、会跑)
    class Bird extends Animal implements IFly, IRun {public Bird(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println(name + " 吃虫子");}@Overridepublic void fly() {System.out.println(name + " 拍打翅膀飞行");}@Overridepublic void run() {System.out.println(name + " 用爪子奔跑");}
    }// 子类:鱼(会游泳)
    class Fish extends Animal implements ISwim {public Fish(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println(name + " 吃鱼食");}@Overridepublic void swim() {System.out.println(name + " 摆尾游泳");}
    }
    
    优势 1:行为更精准
    • Bird 只实现 IFly 和 IRun,因此只有 “飞行” 和 “奔跑” 行为,符合实际特性。
    • Fish 只实现 ISwim,因此只有 “游泳” 行为,也符合实际特性。

    优势 2:扩展性强
    • 如果新增 “兔子(只会跑)”,只需让它实现 IRun 即可,不会继承多余行为。
    • 如果需要修改 “飞行” 行为(比如新增 “昆虫飞行”),只需定义新的 IFly 实现类(如 Insect),不会影响其他类。

    优势 3:遵循设计原则
    • 单一职责:每个接口只负责一种行为,每个类只负责自己的核心特性。
    • 开闭原则:新增行为时,只需新增接口 / 实现类,无需修改已有代码。

    http://www.lryc.cn/news/623946.html

    相关文章:

  • Android中切换语言的方法
  • DNS总结
  • 【Linux内核】Linux信号机制
  • linux 常用代码
  • nodejs 错误处理
  • Collections.synchronizedList是如何将List变为线程安全的
  • vs studio 2017项目不支持studio vs2022
  • 【k8s】Kubernetes核心概念与架构详解
  • 从0实现系统设计
  • Leetcode 15 java
  • GitHub Copilot:AI编程助手的架构演进与真实世界影响
  • 浜掕仈缃戝ぇ鍘侸ava姹傝亴鑰呴潰璇曠幇鍦猴細褰撲弗鑲冮潰璇曞畼閬囦笂鎼炵瑧绋嬪簭鍛樿阿椋炴満
  • Conda 环境 在AI 私有化部署 有怎么用?
  • 电力设备状态监测与健康管理:基于多源异构数据融合的技术实现
  • 五、redis入门 之 客户端连接redis
  • 计算机网络 HTTP1.1、HTTP2、HTTP3 的核心对比及性能分析
  • ReactNode 类型
  • Java项目中短信的发送
  • 密码学系列 - 零知识证明(ZKP) - 多种承诺方案
  • Java ConcurrentHashMap 深度解析
  • 【LeetCode 热题 100】(八)二叉树
  • EC11编码器
  • 集成电路学习:什么是SIFT尺度不变特征变换
  • 43 C++ STL模板库12-容器4-容器适配器-堆栈(stack)
  • 基于DSP+ARM+FPGA架构的储能协调控制器解决方案,支持全国产化
  • 电子电气架构 --- 自动驾驶汽车的下一步发展是什么?
  • 下降路径最小和
  • 【网络通信】TCP/IP 协议全方位解析​
  • java如何把字符串数字转换成数字类型
  • OpenCV 图像处理核心技术:边界填充、算术运算与滤波处理实战