You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中对应Kotlin协变(out)与逆变(in)修饰符的实现方式

Java中泛型协变(out)与逆变(in)的实现方式

Java没有Kotlin中直接在泛型参数声明处标注out/in的语法,而是通过通配符和方法签名约束来实现类似的变体效果,以下是具体实现方式:

一、协变(对应Kotlin的out)

协变适用于泛型类型作为生产者(仅用于返回值,不用于方法参数)的场景,保证子类类型的泛型实例可以安全赋值给父类类型的泛型引用。

1. 使用处协变(通配符? extends)

在使用泛型时,通过? extends 上限类型声明协变:

// 可以将Box<SubType>安全赋值给Box<? extends SomeType>
Box<? extends SomeType> box = new BoxImpl<SubType>(new SubType());

2. 定义支持协变的接口

要让接口本身具备协变特性(让Kotlin能识别并使用out T实现),需要确保接口的泛型参数T仅出现在方法的返回值位置,不允许作为方法参数:

public interface Box<T extends SomeType> {
    // 仅作为返回值,符合生产者特性
    T getItem();

    // 禁止添加此类方法,否则T会成为消费者,破坏协变
    // void setItem(T item);
}

此时Kotlin实现该接口时,使用out T的报错是因为Java泛型默认是不变的,但由于接口仅暴露生产者方法,这个协变实现是安全的,可以添加@Suppress("VARIANCE_MISMATCH")忽略编译器提示,或者直接去掉out(实际使用时可通过Java通配符实现协变)。

二、逆变(对应Kotlin的in)

逆变适用于泛型类型作为消费者(仅用于方法参数,不用于返回值)的场景,保证父类类型的泛型实例可以安全赋值给子类类型的泛型引用。

1. 使用处逆变(通配符? super)

在使用泛型时,通过? super 下限类型声明逆变:

// 可以将Box<SomeType>安全赋值给Box<? super SubType>
Box<? super SubType> box = new BoxImpl<SomeType>();

2. 定义支持逆变的接口

要让接口本身具备逆变特性,需要确保接口的泛型参数T仅出现在方法的参数位置,不允许作为返回值:

public interface ConsumerBox<T extends SomeType> {
    // 仅作为方法参数,符合消费者特性
    void setItem(T item);

    // 禁止添加此类方法,否则T会成为生产者,破坏逆变
    // T getItem();
}

此时Kotlin实现该接口时,可以直接使用in T,编译器会识别到T仅作为输入,支持逆变。


内容的提问来源于stack exchange,提问作者Matthew Layton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 12:25:30