Java:接口和接口调用的理解
前言:
笔者在接触接口的时候比较好理解,但是对接口调用一直是迷迷糊糊,现在学习android开发
的时候经常设计java接口调用,现在来填窟窿了,总结一下。
接口
想必接口大家一定不陌生。
-
接口是一种抽象类型,它只包含方法签名(方法的名称、参数列表和返回类型),而没有方法的实现。在 Java 中,接口使用
interface
关键字来定义。-
public interface MyInterface { void method1(int parameter); String method2(); }
说白了,java接口就是一个标准,说你小子要是想插入这个接口,就必须要符号我这个接口的规范,我这个接口规定了你那边必须要有和我一样的函数名称、返回类型、参数列表,可以说除了函数体之外一模一样。函数体的实现逻辑就由这个接入的类来重写。
到这里有人问了,这和子类继承父类重写父类方法有些类似啊,这玩意有啥用啊。见下文。
与类不同,一个类只能继承一个父类,但一个类可以实现多个接口。简单来嗦,生理上你只能有一个父亲,但是有很多人可以规范你的行为。
-
-
常量:接口中除了抽象方法还可以写入常量:这些常量默认是
public static final
的,即它们是公共的、静态的、不可变的。public interface MyInterface { int CONSTANT_VALUE = 10; void method1(int parameter); }
在介绍接口回调之前,先复习一下继承的部分关键知识,怕有些同学会混淆记忆。
继承
成员变量
子类父类中不同名的成员变量之间无影响,出现重名变量时子类优先访问自己对象中的成员变量,若要访问父类中非私有的成员变量时使用super
关键字.
成员方法
子父类中出现不重名成员方法时调用无影响;子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。
构造方法
继承后子类构方法器特点:子类所有构造方法的第一行都会默认先调用父类的无参构造方法
- 子类构造方法执行的时候,都会在第一行默认先调用父类无参数构造方法一次。
- 子类构造方法的第一行都隐含了一个**super()**去调用父类无参数构造方法,**super()**可以省略不写。
在Java中,子类可以使用super
关键字来调用父类的构造函数:
class Parent {
int x;
Parent(int x) {
this.x = x;
}
}
class Child extends Parent {
int y;
Child(int x, int y) {
super(x); // 调用父类的构造函数
this.y = y;
}
}
上转型与下转型
-
向上转型:将一个子类对象赋值给一个父类类型的变量,这个称为上转型。举个例子
class Animal { public void eat() { System.out.println("Animal is eating"); } } class Dog extends Animal { @Override public void eat() { System.out.println("Dog is eating"); } public void bark() { System.out.println("Dog is barking"); } }
- 此时上转型即为:
Animal a = new Dog()
直白点说,以父类类型来定义这个变量,就是告诉编译器我这个变量是父亲类型的,所以只能调用子类中重写父类的同名方法或者父类的方法,其他特殊方法是找不到的哦。
- 通过变量
a
调用方法时,只能调用Animal
类中定义的方法或者在Dog
类中重写Animal
类的方法。例如,a.eat()
会调用Dog
类中重写后的eat
方法,输出Dog is eating
。但是,不能通过a
直接调用Dog
类中特有的方法,如bark
方法。 - 如果有多个子类都重写了
Animal
类的eat
方法,当通过Animal
类型的变量引用不同子类对象时,会执行相应子类中重写后的eat
方法。这个就是所谓的多态了。 - 当子类没有重写父类的方法时,调用了该方法,则编译器会沿着继承链向上查找,直到找到方法定义或者到达
Object
类。因此,上转型这个模式非常适合写具有多次继承的分层结构。
-
向下转型:
先上概念:
- 接口回调是一种设计模式,它允许一个对象(通常称为客户端)将一个接口的实现传递给另一个对象(通常称为服务提供者)。服务提供者在适当的时候会调用这个接口中的方法,从而实现回调。
有点绕,简单来说,就是我一个方法的参数类型是一个接口,如shape
,而这个接口的具体实现呢是一个对象里面写的。
public interface Shape {
void draw();
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a circle");
}
}
public class GraphicsEngine {
public void drawShape(Shape shape) {
shape.draw();
}
}
public class Main {
public static void main(String[] args) {
GraphicsEngine engine = new GraphicsEngine();
Shape circle = new Circle();
//一开始疑惑这个用接口类型来声明的,其实是把实现了某个接口的具体类的对象赋值给该接口类型的变量。这样实现多态,具有相同名称的接口的类都可以这样赋值对象,实现接口回调
engine.drawShape(circle);
}
}
现实应用:
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
Button button = new Button("Click me");
// 定义事件处理逻辑
//函数式接口 就一个方法
EventHandler<ActionEvent> eventHandler = new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("Button clicked");
}
};
button.setOnAction(eventHandler);
VBox layout = new VBox(10);
layout.getChildren().add(button);
Scene scene = new Scene(layout, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
}
几个重点:
-
匿名内部类:在定义类的同时创建该类的一个实例,过程中不出现新类的名称。假设不使用匿名内部类方法,需要实现一个类
extends
一个接口,然后实现方法,很繁琐。//匿名内部类,直接实现接口方法 EventHandler<ActionEvent> eventHandler = new EventHandler<ActionEvent>() { //<ActionEvent>泛型 ()创建实例 @Override public void handle(ActionEvent event) { System.out.println("Button clicked"); } };
-
接口回调:接受一个
EventHandler<ActionEvent>
接口类型的参数。EventHandler<ActionEvent>
接口定义了一个handle
方法,用于处理动作事件。button.setOnAction(eventHandler);
-
泛型:在
EventHandler<ActionEvent> eventHandler = new EventHandler<ActionEvent>() {... };
这段代码中,EventHandler<ActionEvent>
是一种接口类型声明。EventHandler
本身是一个接口,在 JavaFX 等 GUI 编程环境中,用于处理动作事件(ActionEvent
),它定义了处理这类事件所需要遵循的规范,也就是通过其中抽象的handle
方法来响应事件。
具体说说泛型:泛型是 Java 语言中的一种特性,它允许在定义类、接口、方法时使用类型参数,使得这些类型在使用时可以被指定为具体的类型,从而增强代码的通用性、安全性以及可读性。通过泛型,可以编写能够处理多种不同类型数据的代码,同时在编译阶段就能避免一些类型不匹配的错误。
举个例子:
//类、接口和方法中,使用尖括号 <> 包围类型参数
//泛型
public class Box<T> {
private T content;
public void setContent(T content) {
this.content = content;
}
public T getContent() {
return content;
}
}
//实例化
Box<String> stringBox = new Box<>();
//这里 Box<String> 表示 Box 类的类型参数 T 被指定为 String 类型。
接口回调和子类继承同一个父类调用相同方法区别就是不需要所有类去继承同一个父类,只要有一个相同接口即可,非常灵活和实现解耦。具体一点,假设我想要一些不同父类底下的子类具有某一相同的方法,不需要把这些子类的父类再继承同一个父类来写方法
再以以上的
button
按钮举例,我想要new出来的button
有可自定义内容的handle
方法,直接用匿名内部类实现即可。
参考:
[1] java 泛型类 如何new | PingCode智库
[2] https://www.doubao.com/