Android中关于接口的一些使用技巧与方法

作为一个 Android 开发初学者,每当别人提到“接口”这个词时,我内心总会毫不在意地想:“接口?不就是 implements 一下就完事了吗?”然而,真正开始做项目后才发现,原来接口的使用远不止定义几个方法那么简单。很多关于接口的应用技巧和设计思想,在实际开发中常常被我忽略。你是否也曾遇到过类似的情况呢?让我们一起来深入探讨一下吧!

一.通过接口使用实现类的对象

通过接口使用实现类的对象体现的是多态的理念,他的核心是面向接口编程.实现类必须实现接口中定义的所有抽象方法(除非该类是抽象类).

  1. 基本语法结构

    接口名 变量名 = new 实现类构造器();
    List<String> list = new ArrayList<>();
    list.add("小明");
    

    这行代码的意思是:

    • 左边:接口 List —— 表示你“只关心行为”(比如添加、删除、查找等列表操作).
    • 右边:实现类 ArrayList —— 提供具体的行为实现.
    • 变量名 list —— 是你手中握住的“遥控器”,通过变量名你可以使用对应的方法.

    这就是通过接口来使用实现类对象的经典方式.

  2. 设计思想

    编程时面向接口,而非面向实现。

    松耦合:更容易替换实现类

    可扩展:可以随时替换为 LinkedListCopyOnWriteArrayList 等实现

    易测试:Mock 或 stub 方便替换实现

    更清晰的 API 设计:只暴露该暴露的能力

  3. 自定义接口

    // 1. 定义接口
    public interface Animal {
        void makeSound();
    }
    
    // 2. 实现类
    public class Dog implements Animal {
        public void makeSound() {
            System.out.println("汪汪!");
        }
    }
    
    // 3. 使用接口引用实现类对象
    public class Test {
        public static void main(String[] args) {
            Animal a = new Dog();  // 接口引用指向实现类
            a.makeSound();         // 输出:汪汪!
        }
    }
    
    

    虽然我们拿的是 Animal 类型的遥控器,但背后控制的是 Dog 这台机器。


二.接口作为参数或返回值

“接口作为参数或返回值”"是 Android 和 Java/Kotlin 编程中非常关键的一项技能,尤其是在 回调机制、事件处理、模块解耦 等场景中应用极广。

核心概念:
类型说明
作为参数把某个接口实例传入函数中,用来回调或配置行为
作为返回值函数返回一个接口实例,可以由调用者接收并使用
一、接口作为参数(监听按钮点击后执行某个回调逻辑)
定义一个接口:
interface OnConfirmListener {
    fun onConfirm()
}
函数接受这个接口作为参数:
fun showDialog(listener: OnConfirmListener) {
    // 模拟用户点击确认按钮
    println("用户点击了确认按钮")
    listener.onConfirm()
}

listener.onConfirm(): 这是关键所在。showDialog 函数通过其接收到的 listener 参数(类型是接口),调用了接口中定义的 onConfirm() 方法。此时,showDialog 函数并不知道 listener 参数具体是哪个类的实例,它只知道这个实例有一个 onConfirm() 方法可以被调用。这正是多态的体现。

使用接口对象传递行为:
showDialog(object : OnConfirmListener {
    override fun onConfirm() {
        println("执行确认操作,比如提交表单")
    }
})

showDialog(...): 这里调用了 showDialog 函数。

object : OnConfirmListener { ... }: 这是 Kotlin 中的匿名对象 (Anonymous Object)。它是一个临时的、只使用一次的类实例,并且直接实现了 OnConfirmListener 接口。

override fun onConfirm() { ... }: 在匿名对象内部,我们提供了 onConfirm() 方法的具体实现,也就是当确认事件发生时,我们希望执行的逻辑(例如,“执行确认操作,比如提交表单”)。

目的: 通过这种方式,我们将一个“行为”(onConfirm() 的实现)作为参数传递给了 showDialog 函数。showDialog 在合适的时机(模拟用户点击确认后)会“回调”这个行为。

Kotlin 中还可以使用 Lambda 简化(如果是 SAM 接口):
fun showDialog(onConfirm: () -> Unit) {
    println("用户点击了确认按钮")
    onConfirm()
}

showDialog {
    println("Lambda方式的确认逻辑")
}

fun showDialog(onConfirm: () -> Unit): 这是 Kotlin 的一个强大特性:如果一个接口只包含一个抽象方法(称为 SAM - Single Abstract Method 接口),Kotlin 允许你使用 Lambda 表达式 来简化它的实现。这里的 onConfirm: () -> Unit 表示 onConfirm 是一个函数类型参数,它接受零个参数并返回 Unit(相当于 Java 中的 void)。

onConfirm(): 调用传入的 Lambda 表达式。

showDialog { println("Lambda方式的确认逻辑") }: 这是 Lambda 表达式的调用方式。它提供了一种更简洁、更具函数式编程风格的方式来实现回调。当函数类型参数是最后一个参数时,Kotlin 允许将 Lambda 放在圆括号外部(尾随 Lambda)。


二、接口作为返回值(你希望从某个类中获取“策略”或“处理逻辑”)
定义接口:
interface DataProcessor {
    fun process(data: String)
}
函数返回接口对象:
fun getProcessor(): DataProcessor {
    return object : DataProcessor {
        override fun process(data: String) {
            println("处理数据:$data")
        }
    }
}

fun getProcessor(): DataProcessor: 定义了一个名为 getProcessor 的函数,它声明返回一个 DataProcessor 类型的对象。

return object : DataProcessor { ... }: 这里,getProcessor 函数返回了一个匿名对象,这个匿名对象实现了 DataProcessor 接口。

override fun process(data: String) { println("处理数据:$data") }: 这是匿名对象内部对 process 方法的具体实现。这个实现就是 getProcessor 函数所提供的“处理逻辑”。

调用方使用返回的接口对象:
val processor = getProcessor()
processor.process("Hello from interface!")

val processor = getProcessor(): 调用 getProcessor() 函数,并将返回的 DataProcessor 接口对象赋值给 processor 变量。注意,processor 变量的静态类型是 DataProcessor 接口类型。

processor.process("Hello from interface!"): 通过 processor 接口变量,调用了它所引用的实现类对象中的 process 方法。此时,执行的是 getProcessor 函数内部匿名对象里定义的 process 逻辑。


三.接口的默认方法与函数式接口

你问到了 Java 接口中两个非常现代且实用的特性:默认方法(default methods)函数式接口(functional interfaces)。这两个概念如同接口的“双翼”,一个重在扩展性,一个重在简洁性,帮助接口在面向对象与函数式编程之间架起桥梁。


一、接口的默认方法(Default Method)
定义

Java 8 开始,接口中允许定义带有默认实现的方法,用 default 关键字修饰。

public interface Animal {
    void makeSound();

    // 默认方法:可以被实现类继承或重写
    default void breathe() {
        System.out.println("呼吸空气...");
    }
}
示例
public class Dog implements Animal {
    public void makeSound() {
        System.out.println("汪汪!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal a = new Dog();
        a.makeSound();   // 汪汪!
        a.breathe();     // 呼吸空气...
    }
}

二、函数式接口(Functional Interface)
定义

函数式接口是只包含一个抽象方法的接口,适合用于 Lambda 表达式。

使用 @FunctionalInterface 注解可明确声明该意图:

@FunctionalInterface
public interface Calculator {
    int calc(int a, int b); // 只允许一个抽象方法

    default void printResult(int result) {
        System.out.println("结果是:" + result);
    }
}
示例:使用 Lambda 表达式
public class Main {
    public static void main(String[] args) {
        // 使用 Lambda 表达式实现函数式接口
        Calculator add = (a, b) -> a + b;
        Calculator mul = (a, b) -> a * b;

        int r1 = add.calc(2, 3);
        int r2 = mul.calc(4, 5);

        add.printResult(r1); // 结果是:5
        mul.printResult(r2); // 结果是:20
    }
}

特性接口默认方法函数式接口(Functional Interface)接口多态(通过接口使用实现类的对象)接口作为参数或返回值
出现版本Java 8Java 8Java 基础特性Java 基础特性
方法数量可有多个方法(含默认实现)只能有一个抽象方法接口中定义的所有抽象方法接口中定义的抽象方法(可含默认方法)
使用关键字default@FunctionalInterface(建议加)interfaceimplementsinterface + 参数/返回类型为接口
可否有默认方法✅ 可以✅ 可以✅ 可以(Java 8 起)✅ 可以(Java 8 起)
使用优势向后兼容,减少重复逻辑适配 Lambda,简洁表达函数逻辑解耦结构、支持多态、便于扩展与维护增强灵活性、支持回调、适配不同实现类
使用场景接口升级、代码复用Lambda 表达式、方法引用、回调、流式操作等多态调用、策略模式、面向接口设计、依赖注入等回调机制、策略模式、工厂方法、依赖注入等
表现形式在接口中用 default 修饰方法用 Lambda 表达式实现:(a, b) -> a + b接口名 obj = new 实现类();void func(接口名 obj) / 接口名 getObj()

通过上面的内容,我们一起回顾了在 Android 实际项目中常见的三个接口使用方式和一些实用技巧。接口虽然简单,但灵活运用起来却大有学问。希望这些内容能在你今后的开发过程中带来启发和帮助!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值