在Kotlin
//泛型 generics 变量类型的参数化
//创建一个var T,将构造变量T传入属性T
class MyGeneric<T>(t: T) {
var variable: T
//初始化变量t(必须)
init {
this.variable = t
}
}
class MyClass2<out T, in M>(t: T, m: M) {
//创建有2变量数据类型的泛型类
//out代表生产者,只能读取,类似java的<? extend E>协变
//in代表消费者,只能写入,类似java的<? super E>逆变,String看你所需要的类型
private var t: T
private var m: M
//初始化var t,m from out t,in m
init {
this.t = t
this.m = m
}
// 协程 out t只能读取,so 只能get()
fun get(): T = this.t
// 逆程 in m只能写入,so 只能 set方法
fun set(m: M) {
this.m = m
println(m is Number)
}
}
//这个Test需要关注的是协变的泛型范围
fun myTest(myClass: MyClass2<String, Number>) {
//注意 String写入MyClass2是读取,<? extend object>协变
//Number读取MyClass是写入,<? super String>逆变
val myObject: MyClass2<Any, Int> = myClass
println(myObject.get())//读取Any 写入都是Number
}
fun main(args: Array<String>) {
// 创建MyGeneric<String>的泛型的类
// 类型推断 尖括号可以省略
val myGeneric2 = MyGeneric("hello world")
println(myGeneric2.variable)
println("---------------------------")
val myClass = MyClass2<String, Number>("abc", 3.2)
myTest(myClass)
}
output:
hello world
---------------------------
abc
在java
public class MyTest {
public static void main(String[] args) {
// List<String> list = new ArrayList<String>();
// //报错代码
// List<Object> list2 = list;
// list2.add(3);
// String str = list2.get(0);
/*--------------PECS Producer Extends,Consumer Super------------*/
List<Cat> cats = new ArrayList<Cat>();
//放入Animal或者Animal的子类 协变
List<? extends Animal> animals = cats;
//不能写入 因为并不能知道animals列表具体的是List<Cat>还是List<Dog>只能知道是Animal或者其子类的List
//animals.add(new Cat());
List<Animal> animals1 = new ArrayList<>();
//放入Animal或者Animal父类 写入的时候 父类转子类所以可以写入
List<? super Animal> contravariant = animals1;
contravariant.add(new Animal());
contravariant.add(new Cat());//多态
contravariant.add(new Dog());//多态
//contravariant.add(new Object());//实际类型是Animal
//这样可行
List<Object> list = new ArrayList<>();
list.add(new Object());
List<? super Animal> contravariant1 = list;
//contravariant1.add(new Object());
//不能读取 只能知道是Animal的父类 不知道是Object 还是其他的 父类转子类是错误的
//Animal animal = contravariant.get(0);
/*-----------------------------------------*/
//类型是Object 指向String数组,Java数组支持协变逆变,不过会出现一些问题
Object[] objs = new String[]{"aaa", "bbb"}; //协变
objs[0] = new Object();//错误做法把String元素改成了Object对象
}
}
class Animal {
}
class Cat extends Animal {
}
class Dog extends Animal {
}
output:
协变逆变区别
public class xiebiannibian {
public static void main(String[] args) {
// 协变(covariant)和逆变(controversial)
List<Object>
List<String>
//List<String> 不是 List<Object>的子类 List不支持协变
List<String> list = new ArrayList();
List<Object> list2 = list; //编译失败
list2.add (new Date( ) );
String str = list.get(0);
//通配符的出现 解决上面问题
List<? extends Object> list ...
interface Collection<E> {
void addAll(Collection<E> items)
}
interface Collection<E> {
//错误做法
void addAll(Collection<E> items)
//java库 实际上是这样的
//可以随意的把集合内容当作E来读取而不当作实际类型来读取
// 而不能随意的写入修改内容 ,因为可以添加E的任意子类实例 但是不知道实际类型
boolean addAll(Collection<? extends E> c);
//Number或其子类
}
void copyAll(Collection<Object> to, Collection<String> from) {
to.addAll(from)
}
//被限制了上界 只能读取 读取到的当作E 叫做协变 生产者
// Collection<String> 就是Collection<? extends Object>的子类型 而不是Collection<Object>;
//限定了只能放入String的父类 只能写入成String 是类型安全的 叫做逆变 消费者
//List<? super String>
//List<? super E>
List<? super Number> list001 = new ArrayList<Number>();
//Object或其他Number的父类
list001.add(new Integer(3));
list001.add(new Float(2.1));
List<? super Number> list002 = new ArrayList<Object>();
list002.add(3);
list002.add(1);
}
}