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. LSP
It 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>();
}
}
java
In 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, NUmber
all 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, super
generics 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;
}
}