协变(Covariance)和反协变(Contravariance)

在面向对象编程和类型系统中,协变(Covariance)和反协变(Contravariance)是处理类型继承和子类化关系的重要概念。这些概念主要用于理解和管理类型在泛型、方法返回类型、参数类型等场景中的行为。以下是对协变和反协变的详细解释。

协变(Covariance)

协变是指类型可以从子类型转换为父类型。换句话说,如果类型 B 是类型 A 的子类型,那么 B[] 也是 A[] 的子类型。协变通常适用于返回类型,即允许方法的返回类型是其声明的返回类型的子类型。

示例:数组的协变

在Java中,数组是协变的。这意味着你可以将一个子类数组赋值给一个父类数组的引用。

public class Main {
    public static void main(String[] args) {
        Integer[] integers = {1, 2, 3};
        Number[] numbers = integers; // 数组是协变的

        numbers[0] = 1.5; // 运行时会抛出 ArrayStoreException
    }
}

尽管数组在Java中是协变的,但这种协变可能会导致运行时错误,如上例中的 ArrayStoreException

示例:泛型的协变(使用通配符)

在Java泛型中,可以使用通配符 ? extends T 来实现协变。

import java.util.List;
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        List<Integer> integerList = new ArrayList<>();
        List<? extends Number> numberList = integerList; // 泛型协变

        // 不能向 numberList 添加元素,因为编译器无法确定类型的安全性
        // numberList.add(1); // 编译错误

        Number num = numberList.get(0); // 读取是安全的
    }
}

在这个示例中,List<? extends Number>List<Integer> 的父类型,这实现了泛型的协变。

反协变(Contravariance)

反协变是指类型可以从父类型转换为子类型。换句话说,如果类型 A 是类型 B 的子类型,那么 A[] 可以被看作是 B[] 的子类型。反协变通常适用于方法的参数类型,即允许方法的参数类型是其声明的参数类型的父类型。

示例:泛型的反协变(使用通配符)

在Java泛型中,可以使用通配符 ? super T 来实现反协变。

import java.util.List;
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        List<Integer> integerList = new ArrayList<>();
        List<? extends Number> numberList = integerList; // 泛型协变

        // 不能向 numberList 添加元素,因为编译器无法确定类型的安全性
        // numberList.add(1); // 编译错误

        Number num = numberList.get(0); // 读取是安全的
    }
}

在这个示例中,List<? super Integer>List<Number> 的父类型,这实现了泛型的反协变。

协变和反协变的应用

  1. 方法返回类型的协变:子类方法可以返回比父类方法更具体的类型。
  2. 方法参数类型的反协变:子类方法可以接受比父类方法更通用的参数类型。
  3. 泛型的协变和反协变:使用通配符 ? extends T? super T 来实现泛型类型的协变和反协变。
示例:方法返回类型的协变
class Animal {
    public Animal getAnimal() {
        return new Animal();
    }
}

class Dog extends Animal {
    @Override
    public Dog getAnimal() {
        return new Dog(); // 返回类型的协变
    }
}

示例:方法参数类型的反协变

class Processor<T> {
    public void process(T item) {
        // 处理 item
    }
}

class IntegerProcessor extends Processor<Number> {
    @Override
    public void process(Number item) {
        // 处理 Number 类型的 item
    }
}

在这个示例中,IntegerProcessor 类中的 process 方法接受 Number 类型的参数,而不是 Integer 类型的参数,这是方法参数类型的反协变。

总结

  • 协变(Covariance):允许子类型转换为父类型,主要应用于返回类型。例如,List<? extends T> 实现了协变。
  • 反协变(Contravariance):允许父类型转换为子类型,主要应用于参数类型。例如,List<? super T> 实现了反协变。

通过理解和应用协变和反协变,可以编写更加灵活和通用的代码,特别是在处理泛型和多态性时。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值