当前位置: 首页
编程语言
Java中Function接口接收子接口类型参数的方法与示例

Java中Function接口接收子接口类型参数的方法与示例

热心网友 时间:2026-07-08
转载
要让一个接受 Function 的方法也能安全接收 Function(其中 B extends A),需将参数声明为 Function,这正是 PECS 原则在逆变场景下的典型应用,从而实现类型安全的协变兼容。

先说结论:在 Java 泛型的世界里,Function 和 Function 之间并不是父子关系——哪怕 B 确实继承了 A,这两个函数类型也是不变的(invariant)。这意味着你无法直接把 Function 传给一个要求 Function 的变量——编译器会直接拒绝,因为类型不安全。

问题的本质在于:你真正想要的是把一个 B 的实例传入函数,而这个函数需要能够处理 B 或者 B 的任意父类型(比如 A)。此时就该让逆变(contravariance)出场了:使用 ? super B 来表示“这个函数能接受 B 或者 B 的任意超类”。简单来说,就是声明为 Function

那么,具体如何实现?看一段实际代码就清楚了:

// 接口定义
public interface Displayable {}
public interface Purchasable extends Displayable {}

// 构造器或方法签名(关键!)
public class DisplayablePanel {
    private final Function displayTextFn;

    public DisplayablePanel(Function fn) {
        this.displayTextFn = fn;
    }

    public void render(Purchasable item) {
        String label = displayTextFn.apply(item); // ✅ 安全调用
        // ... 使用 label 创建 UI 元素
    }
}

这样设计之后,下面几种函数都能顺利传入——宽松程度各不相同,但全部合法:

// ✅ 接受 Purchasable(最具体)
Function purchasableFn = p -> p.getName() + " ($" + p.getPrice() + ")";

// ✅ 接受 Displayable(更宽泛,仍兼容)
Function displayableFn = d -> d.toString();

// ✅ 甚至接受 Object(极端宽泛,但合法)
Function objectFn = obj -> "[Object: " + obj.getClass().getSimpleName() + "]";

new DisplayablePanel(purchasableFn);     // 编译通过
new DisplayablePanel(displayableFn);     // 编译通过
new DisplayablePanel(objectFn);          // 编译通过

有几个要点值得特别提醒:

  • ❌ 千万别用 Function——方向完全反了。? extends A 表示“返回 A 的子类型”,但 apply() 方法需要的是输入参数。对输入来说,? extends A 是只读不安全的,无法保证你传入的 B 能被这个函数接受。
  • ✅ ? super B 遵循的是经典的 PECS 原则(Producer Extends, Consumer Super)。注意,Function 的第一个类型参数是消费者——它消费输入对象,所以用 super 才对。
  • 这个方案完全不会破坏类型安全。道理很简单:B 是 A 的子类型,任何能处理 B 的函数自然能处理 B 的实例;而 ? super B 允许函数处理 B、A 甚至 Object 这些更宽泛的类型,恰好满足“所有 Purchasable 都是 Displayable”这个设计意图。

一句话总结:当你需要函数参数支持子类型的实参时,不要试图把函数本身向上转型——那条路不通。正确的做法是通过 ? super SubType 来重新定义函数类型边界。这才是 Java 泛型中实现既安全又灵活的接口适配的正确方式。

来源:https://www.php.cn/faq/2787475.html

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
列表遍历时动态判断阈值并返回相应文本

列表遍历时动态判断阈值并返回相应文本

遍历数值列表时,先筛选满足阈值的元素,再根据结果输出列表或友好提示。推荐使用列表推导式结合条件判断,注意边界用`>=`,空列表自动为假。也可用`any()`提前终止遍历,提升效率。此法简洁,避免显式循环,特别适合阈值筛选。

时间:2026-07-08 06:50
Maven项目中如何强制使用本地构建的依赖版本

Maven项目中如何强制使用本地构建的依赖版本

多模块开发中强制使用本地依赖的正确做法是使用-SNAPSHOT版本并配合`-U`参数强制更新,或重构为多模块项目统一管理生命周期。避免使用版本范围语法或手动复制JAR,确保构建行为可靠可重复。

时间:2026-07-08 06:50
Go语言net.Conn并发写安全与原子性保障解析

Go语言net.Conn并发写安全与原子性保障解析

Go标准库中net Conn支持并发方法调用,但Write()不保证原子性。多goroutine同时写入时,系统可能拆分数据包,导致内容交错,破坏消息边界。必须使用互斥锁或bufio Writer等显式同步机制确保写操作完整性,不可依赖系统调用本身的原子性。

时间:2026-07-08 06:50
Python在Windows系统中获取指定卷标U盘驱动器字母的方法

Python在Windows系统中获取指定卷标U盘驱动器字母的方法

使用Pythonwmi库通过Win32_Volume接口查询Windows系统中卷标为“TOSHIBA”的U盘盘符。需安装wmi和pywin32,注意大小写区分及多设备过滤。仅适用于Windows。

时间:2026-07-08 06:49
TP6.0消息已读功能基于Redis Bitmap未读计数方案

TP6.0消息已读功能基于Redis Bitmap未读计数方案

TP6 0中使用Redis位图实现消息已读标记,每条消息仅占一个比特,内存效率高。需将消息ID映射为连续偏移量,通过SETBIT和GETBIT操作。需提前维护用户ID到偏移量的映射表,注意键过期与驱动类型(phpredis与predis)问题。此方法内存极省,适合海量消息场景,且需确保偏移量唯一。

时间:2026-07-08 06:49
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 日榜
  • 周榜
  • 月榜