个人理解:
1. 逆变in向上兼容类
2. 协变out向下兼容类
在面向对象编程中,尤其是使用泛型时,in和out关键字用于限制类型参数的协变性和逆变性。
in关键字(逆变):
in关键字用于标记泛型类型参数的逆变性。逆变表示可以使用指定类型的基类或超类作为方法的参数类型。in关键字限定类型参数时,该泛型类型可以被赋值给比它更通用的类型。in Animal,表示该类型参数可以是Animal或其任何基类。out关键字(协变):
out关键字用于标记泛型类型参数的协变性。协变表示可以使用指定类型的子类或派生类作为方法的返回类型。out关键字限定类型参数时,该泛型类型可以被赋值给比它更具体的类型。out Animal,表示该类型参数可以是Animal或其任何派生类。通过使用in和out关键字,我们可以在泛型类型参数中限制类型的协变性和逆变性,以确保类型安全性。这样做的好处是能够更容易地对泛型类型进行复用和灵活性。
代码示例:
- // 声明一个只读存储库接口,用于查询动物信息
- interface ReadOnlyRepository<out T> {
- fun getAll(): List
- fun getById(id: String): T?
- }
- // 声明一个只写存储库接口,用于添加动物
- interface WriteOnlyRepository<in T> {
- fun add(item: T)
- }
- // Animal类作为基类
- open class Animal(val name: String)
- // Dog类继承自Animal
- class Dog(name: String) : Animal(name)
- // Cat类继承自Animal
- class Cat(name: String) : Animal(name)
- // 只读存储库实现
- class ReadOnlyAnimalRepository : ReadOnlyRepository
{ - private val animals = listOf(Animal("Lion"), Dog("Buddy"), Cat("Whiskers"))
-
- override fun getAll(): List
{ - return animals
- }
-
- override fun getById(id: String): Animal? {
- return animals.find { it.name == id }
- }
- }
-
- // 只写存储库实现
- class WriteOnlyAnimalRepository : WriteOnlyRepository<Animal> {
- private val animals = mutableListOf
() -
- override fun add(item: Animal) {
- animals.add(item)
- }
- }
-
- fun main() {
- val readOnlyRepo: ReadOnlyRepository
= ReadOnlyAnimalRepository() - val writeOnlyRepo: WriteOnlyRepository
= WriteOnlyAnimalRepository() -
- val allAnimals = readOnlyRepo.getAll()
- println("All Animals:")
- allAnimals.forEach { animal ->
- println("- ${animal.name}")
- }
-
- val dog1 = Dog("Max")
- writeOnlyRepo.add(dog1)
- println("\nAdded Dog:")
- val addedDog = readOnlyRepo.getById(dog1.name)
- println("- ${addedDog?.name}")
-
- val cat1 = Cat("Misty")
- // writeOnlyRepo.add(cat1) // Compilation Error: Type mismatch. Required: Dog, Found: Cat
- }
在上面的代码示例中,我们定义了两个存储库接口:ReadOnlyRepository和WriteOnlyRepository。ReadOnlyRepository接口声明了返回类型out T,表示它只能查询(读取)动物信息。WriteOnlyRepository接口声明了参数类型in T,表示它只能添加(写入)动物。
然后,我们创建了一个ReadOnlyAnimalRepository类来实现ReadOnlyRepository接口,用于查询动物信息。同样地,我们还创建了一个WriteOnlyAnimalRepository类来实现WriteOnlyRepository接口,用于添加动物。
在main函数中,我们首先将ReadOnlyAnimalRepository赋值给readOnlyRepo变量,这是合法的,因为ReadOnlyAnimalRepository实现了ReadOnlyRepository接口。
然后,我们将WriteOnlyAnimalRepository赋值给writeOnlyRepo变量,这也是合法的,因为WriteOnlyAnimalRepository实现了WriteOnlyRepository接口。注意,虽然我们将其赋值给writeOnlyRepo变量,但我们仍然只能使用add方法添加