[JAVA cold knowledge] What is contravariant and covariant? Does array support covariant & contravariance? What about generics?

write in front


  • Share some small knowledge points with your friends java, mainly around the following points:
  • What is 逆变(contravariant)& 协变(covariant)?
  • 数组support 协变&逆变?
  • 泛型support 协变&逆变?
  • Some content references
    • 《编写高质量代码(改善Java程序的151个建议)》
  • If there is a mistake in the understanding of the blog post, the friends leave a message and private message to discuss together

Life can't wait for others to arrange, you have to fight and struggle yourself; no matter whether the result is happy or sad, but the consolation is that you have lived a life in this world in vain. With this realization, you will appreciate life without being cynical; at the same time, you will infuse yourself with a powerful inner strength. ——Lu Yao "Ordinary World"


As for 协变what 逆变yu means, it's actually very easy to understand. It can be described in one sentence: (When you see the following, will you think that this is what it is 多态? Ha, today we only look at 协变和逆变some 多态of the content, such as 强制多态, 包含多态, 重载多态I will have the opportunity to share it with my friends later)

协变i.e. 窄类型替换宽类型, 逆变i.e.宽类型覆盖窄类型

What 窄类型is 子类(派生类)here, what 宽类型is 父类(基类,超类)here, 替换覆盖what does it mean here, here is OO(面相对象)六大设计one of the principles LSP(里氏代换原则 Liskov Substitution Principle), 里氏代换原则in which it says that wherever 基类it can appear, it 子类must appear. LSPIt is the cornerstone of inheritance and reuse. Only when 派生类it can be replaced 基类and the function of the software unit is not affected, it 基类can be truly reused, and 派生类it can also be added on 基类the basis of it 新的行为.

Let's combine the code to analyze the covariance and contravariance of arrays and generics

Let's look at a piece of code

package com.liruilong;

import java.util.Arrays;

/**
 * @Project_name: workspack
 * @Package: com.liruilong
 * @Description:
 * @Author: [email protected]
 * @WeChat_Official_Accounts: 山河已无恙
 * @blog: https://liruilong.blog.csdn.net/
 * @Date: 2022/2/11  1:18
 */
public class CovariantDemo {
    
    

    public static void main(String[] args) {
    
    
        Number [] numbers = {
    
    1,1L,3d,2.0F};
        Arrays.stream(numbers).forEach(System.out::print);
    }
}

The Number class is the parent class of all basic type encapsulation classes. Similarly, the basic type encapsulation class is a subclass of the Number class. Automatic boxing and automatic unboxing are new features introduced by java in JDK1.5. We don’t have much here. Speaking of, the above code can be compiled normally, and the following content is output. Here, the basic type boxing in the array is placed in the heap for the encapsulated class. These encapsulated classes can appear in the array defined by the Number class, indicating that subclasses can be replaced The parent class, that is, the array is covariant.

113.02.0
Process finished with exit code 0

Now that arrays are supported 协变, then 逆变what? let's see

package com.liruilong;

import java.util.Arrays;

/**
 * @Project_name: workspack
 * @Package: com.liruilong
 * @Description:
 * @Author: [email protected]
 * @WeChat_Official_Accounts: 山河已无恙
 * @blog: https://liruilong.blog.csdn.net/
 * @Date: 2022/2/11  1:18
 */
public class CovariantDemo {
    
    

    public static void main(String[] args) {
    
    
        Number [] numbers = {
    
    new Object()};
        Arrays.stream(numbers).forEach(System.out::print);
    }
}

Here we replace the array elements Object类with, that is, the parent class of all classes, I hope it can pass 父类来覆盖代替子类, but the 直接编译报错description 数组is yes不支持直接逆变

Error:(17, 30) java: 不兼容的类型: java.lang.Object无法转换为java.lang.Number

The array does not support direct inversion, so whether it is possible to achieve inversion, here I will use 多态one of them, 强制多态, that is, 强制类型转化try

package com.liruilong;

import java.util.Arrays;

/**
 * @Project_name: workspack
 * @Package: com.liruilong
 * @Description:
 * @Author: [email protected]
 * @WeChat_Official_Accounts: 山河已无恙
 * @blog: https://liruilong.blog.csdn.net/
 * @Date: 2022/2/11  1:18
 */
public class CovariantDemo {
    
    
    class A {
    
    

    }
    class B extends A{
    
    
      
    }

    public static void main(String[] args) {
    
    
        A a = new CovariantDemo().new A();
        B [] bs = {
    
    (B) a};
        Arrays.stream(bs).forEach(System.out::print);
    }
}

类型转化报错. It means that 数组的逆变, yes 不支持逆变, forcibly converting the parent class into a subclass to report a type conversion exception, java does not limit this aspect.

Exception in thread "main" java.lang.ClassCastException: com.liruilong.CovariantDemo$A cannot be cast to com.liruilong.CovariantDemo$B
	at com.liruilong.CovariantDemo.main(CovariantDemo.java:24)

Process finished with exit code 1

Through the above code, we can know that the array supports covariance and does not support contravariance . What about generics? Whether covariance and contravariance are supported

泛型不支持协变也不支持逆变, that is, can not put one 父类对象赋值给一个子类类型变量, the opposite is also the same.

Let's look at the code below

package com.liruilong;

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

/**
 * @Project_name: workspack
 * @Package: com.liruilong
 * @Description:
 * @Author: [email protected]
 * @WeChat_Official_Accounts: 山河已无恙
 * @blog: https://liruilong.blog.csdn.net/
 * @Date: 2022/2/11  1:18
 */
public class CovariantDemo {
    
    
    public static void main(String[] args) {
    
    
        List<Number> ln = new ArrayList<Integer>();
    }
}

javaIn order to be guaranteed 运行期, 安全性it must be guaranteed 泛型参数类型yes 固定, so it 不允许can 泛型参数contain both 两种类型, even if it is 父子关系not. So directly 编译报错, ie 泛型不支持协变也不支持逆变.

Error:(17, 27) java: 不兼容的类型: java.util.ArrayList<java.lang.Integer>无法转换为java.util.List<java.lang.Number>

But it can be used 通配符(Wildcard)模拟协变逆变, wildcards are valid at compile time and must be an explicit type at runtime

package com.liruilong;

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

/**
 * @Project_name: workspack
 * @Package: com.liruilong
 * @Description:
 * @Author: [email protected]
 * @WeChat_Official_Accounts: 山河已无恙
 * @blog: https://liruilong.blog.csdn.net/
 * @Date: 2022/2/11  1:18
 */
public class CovariantDemo {
    
    
    public static void main(String[] args) {
    
    
        List< ? extends Number > list = new ArrayList<Integer>();
    }
}

That is Number, all subtypes can be generic type parameters, that is, NUmberall subclasses are allowed as generic parameter types, which are a specific value at runtime.编译没有报错


Process finished with exit code 0

Contravariance is also possible, that is, generics can simulate covariance and contravariance through summation, but yes, supergenerics are mainly used here to be effective in the compilerextends本身是不存在协变和逆变

List< ? super Integer> li = new ArrayList<Number>();

About covariant and contravariant, I will share it with my friends here. Well, there is also a covariant contravariant method. I will briefly explain it here.

Covariant method : That is, the type of the return value of the subclass method is narrower than that of the parent class method, that is, the method is a covariant method, also called多态,覆写,重写.

//子类的doStuff()方法返回值的类型比父类方法要窄,即该方法为协变方法,也称多态。
    class A{
    
    
        public  Number doStuff(){
    
    
            return 0;
        }
    }
    class B extends A{
    
    
        @Override
        public  Integer doStuff(){
    
    
            return 0;
        }
    }

Contravariant method : The type of the return value of the method of the subclass is wider than that of the method of the parent class, which is a contravariant method. Although the subclass expands the input and return parameters of the parent class, it is already here重载.

//子类的doSutff方法返回值的类型比父类方法宽,此时为逆变方法,
    class C {
    
    

        public Integer doStuff(Integer i) {
    
    
            return 0;
        }

    }

    class D extends C {
    
    

        public Number doStuff(Number i) {
    
    
            return 0;
        }
    }

Guess you like

Origin blog.csdn.net/sanhewuyang/article/details/122872594