Kotlin과 Java의 공분산과 반공분산을 더 잘 이해하기 위해 먼저 몇 가지 기본 지식을 살펴보겠습니다.
일반 할당
Java에서 공통 할당문은 다음과 같습니다.
A a = b;复制代码
대입문이 충족해야 하는 조건은 다음과 같습니다. 왼쪽이 오른쪽의 상위 클래스이거나 오른쪽과 동일한 유형입니다. 옆. 즉, A 유형은 Object o = new String("s"); 와 같이 B 유형보다 "더 커야" 합니다. 이하에서는 편의상 A> Object o = new String("s"); 。为了方便起见,下文中称作 A > B。
除了上述最常见的赋值语句,还有两种其他的赋值语句:
函数参数的赋值
public void fun(A a) {}// 调用处赋值B b = new B();
fun(b);复制代码
在调用 fun(b) 方法时,会将传入的 B b 实参赋值给形参 A a,即 A a = b 的形式。同样的,必须要满足形参类型大于实参,即 A > B。
函数返回值的赋值
public A fun() {
B b = new B(); return b;
}
复制代码
函数返回值类型接收实际返回类型的值,实际返回类型 B b 相当于赋值给了函数返回值类型 A a,即 B b 赋值给了 A a, 即 A a = b,那么必须满足 A > B 的类型关系。
所以,无论哪种赋值,都必须满足左边类型 > 右边类型,即 A > B。
Java 中的协变与逆变
有了前面的基础知识,就可以方便地解释协变与逆变了。
如果类 A > 类 B,经过一个变化 trans 后得到的 trans(A) 与 trans(B) 依旧满足 trans(A) > trans(B),那么称为协变。
逆变则刚好相反,如果类 A > 类 B,经过一个变化 trans 后得到的 trans(A) 与 trans(B) 满足 trans(B) > trans(A),称为逆变。
但是很抱歉,由于种种原因,Java 并不支持。但是,Java 并不是完全抹杀了泛型的型变特性,Java 提供了 extends T> 和 super T> 使泛型拥有协变和逆变的特性。
extends T> 与 super T>
extends T> 称为上界通配符, super T> 称为下界通配符。使用上界通配符可以使泛型协变,而使用下界通配符可以使泛型逆变。
比如之前举的例子
List<Integer> l = new ArrayList<>();
List<Object> o = l;// 这里会报错,不能编译复制代码
如果使用上界通配符,
List<Integer> l = new ArrayList<>();
List<? extends Object> o = l;// 可以通过编译复制代码
这样,List extends Object> 的类型就大于 List 的类型了,也就实现了协变。这也就是所谓的“子类的泛型是泛型的子类”。
同样,下界通配符 super T> 可以实现逆变,如:
public List<? super Integer> fun(){
List<Object> l = new ArrayList<>(); return l;
}复制代码
上述代码怎么就实现逆变了呢?首先,Object > Integer;另外,从前言我们知道,函数返回值类型必须大于实际返回值类型,在这里就是 List super Integer> > List<object></object>
위에 언급된 가장 일반적인 할당 문 외에도 두 가지 다른 할당 문이 있습니다:
함수 매개 변수 할당
public class Container<T> { private T item; public void set(T t) {
item = t;
} public T get() { return item;
}
}复制代码
🎜fun(b) 메서드를 호출할 때, 전달된 실제 매개변수 B b 는 형식 매개변수 A a 에, 즉 A a = b 형식으로 할당됩니다. 마찬가지로 형식 매개변수 유형은 실제 매개변수보다 커야 합니다. 즉, A > B입니다. 🎜
함수 반환값 지정🎜
Container<Object> c = new Container<String>(); // (1)编译报错Container<? extends Object> c = new Container<String>(); // (2)编译通过c.set("sss"); // (3)编译报错Object o = c.get();// (4)编译通过复制代码
🎜함수 반환값 형식은 실제 반환값 형식의 값을 받습니다. B b 실제 반환값 형식은 함수 반환값 형식을 지정하는 것과 동일합니다. A a, 즉 B b 가 A a, 즉 A a = b에 할당되면 A > B의 유형 관계가 충족되어야 합니다. 🎜🎜그러므로 어떤 종류의 과제라도 left type > right type, 즉 A > B를 만족해야 합니다. 🎜
Java의 공분산과 반공변성🎜🎜이전의 기본 지식으로 공분산과 반공변성을 쉽게 설명할 수 있습니다. 🎜🎜클래스 A > 클래스 B, trans 변경 후에도 얻은 trans(A) 및 trans(B)가 여전히 trans(A) > trans(B)를 만족하는 경우 공변성이라고 합니다. . 🎜🎜역변동은 정반대인 경우, 변경 trans(A)와 trans(B)는 trans(B) > trans(A)를 만족합니다. 역변화. 🎜🎜예를 들어, Java 배열이 공변적이라는 것은 누구나 알고 있습니다. A > B이면 A[] > B[]가 A[]에 할당될 수 있습니다. 예: 🎜
Container<String> c = new Container<Object>(); // (1)编译报错Container<? super String> c = new Container<Object>(); // (2)编译通过
c.set("sss");// (3) 编译通过
String s = c.get();// (4) 编译报错复制代码
🎜그러나 Java의 제네릭은 다음과 같이 공분산을 충족하지 않습니다. 🎜
public class Container<T> { private T item; public void set(T t) {
item = t;
} public T get() { return item;
}
}复制代码
🎜위 코드는 Object > Integer임에도 불구하고 제네릭이 공분산을 충족하지 않기 때문에 오류를 보고합니다. 따라서 List
위 내용은 Java의 Kotlin 공분산과 반공분산에 대해 이야기해 보겠습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!