「java泛型逆变和协变」泛型的协变

博主:adminadmin 2022-12-12 02:27:08 96

今天给各位分享java泛型逆变和协变的知识,其中也会对泛型的协变进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

java in int 类型什么意思?

AIDL是 Android Interface definition language的缩写,一看就明白,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口。

通常我们在定义aidl文件里面的方法的时候,很少注意或者很少用到到参数的修饰符:in 、out 、inout,它们代表的是客户端和服务端数据相互传递的规则。注意,这里只是针对参数的规则,并不是方法返回值的规则。

如下介绍in/out/inout:

in代表参数只能从客户端传到服务端,服务端在执行这个方法的时候,会读取服务端传过来的参数,并以此参数执行方法。在服务端把方法执行完之后,并不会再做其他动作。

out代表此参数从客户端传递不到服务端,也就是在服务端执行方法的时候,并不会去读取客户端的这个参数,而是自己new一个新对象,用此新对象来作为参数执行方法。但是在方法执行完之后,会把这个参数又传回客户端,更新客户端的对象参数值。

inout则是相互之间都是可以传递和感知的。

Java中什么是协变?怎样进行协变?

协变,就是父类和子类保持相同形式的变化,但是协变有时候倍支持,有时候不被支持

比如,在数组中,协变是支持的

比如

class Parent{}

class Child extends Parent{}

那么 Child[]可以赋值给 Parent[] ,这个就是协变

但是,在泛型中,协变就不可以

比如 虽然Child extends Parent

但是,假设有个 TestT,则 TestChild不可以赋值给TestParent,这2者毫无关系

泛型和数组以及Java是如何实现泛型的

要区分数组和泛型容器的功能,这里先要理解三个概念:协变性(covariance)、逆变性(contravariance)和无关性(invariant)。

若类A是类B的子类,则记作A ≦ B。设有变换f(),若:

当A ≦ B时,有f(A)≦ f(B),则称变换f()具有协变性;

当A ≦ B时,有f(B)≦ f(A),则称变换f()具有逆变性;

如果以上两者皆不成立,则称变换f()具有无关性。

在Java中,数组具有协变性,而泛型具有无关性,示例代码如下:

Object[] array = new String[10];

//编译错误

ArrayListObject list=new ArrayListString();

这两句代码,数组正常编译通过,而泛型抛出了编译期错误,应用之前提出的概念对代码进行分析,可知:

1、String ≦ Object

2、数组的变换可以表达为f(A)=A[],通过之前的示例,可以得出下推论:

f(String) = String[] 以及 f(Object) = Object[];

4、通过代码验证,String[] ≦ Object[] 是成立的,由此可见,数组具有协变性。

逆变和协变到底有什么区别

关于协变和逆变要从面向对象继承说起。继承关系是指子类和父类之间的关系;子类从父类继承所以子类的实例也就是父类的实例。比如说Animal是父类,Dog是从Animal继承的子类;如果一个对象的类型是Dog,那么他必然是Animal。

协变逆变正是利用继承关系 对不同参数类型或返回值类型 的委托或者泛型接口之间做转变。我承认这句话很绕,如果你也觉得绕不妨往下看看。

如果一个方法要接受Dog参数,那么另一个接受Animal参数的方法肯定也可以接受这个方法的参数,这是Animal向Dog方向的转变是逆变。如果一个方法要求的返回值是Animal,那么返回Dog的方法肯定是可以满足其返回值要求的,这是Dog向Animal方向的转变是协变。

什么是协变, 逆变?

java中协变跟逆变是对泛型类的继承关系的表述.

如:

ListNumber 和 ListInteger 之间是没有继承关系的.

但是直观上会觉得, Integer 是 Number 的子类, 所以 ListInteger 应是 ListNumber 的子类.

如果想要这种效果, 就要用协变.

List? extends Number 这样 ListInteger 就能成为List? extends Number 子类, 也就是可以赋值

这里如果你想要相反的效果, 则用逆变, List? super Number 这样继承关系就会相反.

那么什么时候用协变,逆变?

协变主要是用在函数的返回值上,逆变用在函数参数上,这样的规则也就能遵循 里氏替换原则 .

如 Function , 在这里 R 作为函数的返回值, 所以这个泛型要协变, 而 T 用在函数的参数上所以要用逆变

这里举个例子

假设有以下继承关系:

车 轿车 标准轿车 高级轿车

现在有一个人声称自己能修理所有的标准轿车, 所以发出了以下公告:

假设我现在有 List轿车 和 List高级轿车

那么这个人到底能修理哪个呢? 从上面的函数声明来看都不可以.

再来看看这个人的声明

他说能够修理所有 标准轿车

那么因为标准轿车扩展了轿车, 所以如果能够修理标准轿车, 那么应当可以修理轿车

所以这个函数应当可以接受所有 标准轿车 的父类

也就是说 List轿车 能够传入 以 List标准轿车 为参数的函数

换句话说 List轿车 是 List标准轿车 的子类, 这样才能传入参数

所以上面的公告要用逆变, 改成如下:

也许也不会有人想把自己的高级轿车交给这家伙.

以此类推, 函数的返回值应当用协变, 这样既能满足 里氏替换原则 了

kotlin 协变与逆变

kotlin中没有像java一样的? extends T这样的方式,也没有父类向子类转换,但是为了数据的安全性,提出了协变与逆变的说法:

概念:

协变:类型向上转换,像java中的子类向父类转换

逆变:类型向下转换,父类向子类转换

特点:

协变只能出现在返回值中,逆变只能出现在方法的参数中,还有一种既不是协变也不是逆变的类型,什么地方都可以使用例如:

因为其中的T 出现在了全局变量的地方,所以既不是协变也不是逆变。

逆变的情况(作为参数传入并且不能接受BaseActivityView的泛型作为返回值):

协变的情况(作为返回值并且不能接受BaseActivityView的泛型作为参数传入):

使用场景:

可以移步这里进行更深层次理解

关于java泛型逆变和协变和泛型的协变的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。

The End

发布于:2022-12-12,除非注明,否则均为首码项目网原创文章,转载请注明出处。