kotlin的in和out

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
class Result<T>{
private T data;
public Result() {
}
public Result(T data) {
this.data = data;
}

public T getData() {
return data;
}

public void setData(T data) {
this.data = data;
}
}

1. 不可型变

1
2
Result<Dog> dogResult = new Result<>();
Result<Animal> animalResult = dogResult; // 编译报错

虽然DogAnimal的孩子,但是Java泛型是不可变型变,所以Result不可以赋值给Result.如果可以的话会发生什么情况呢?

1
2
3
4
5
6
7
8
Result<Dog> dogResult = new Result<>();
Result<Animal> animalResult = dogResult;//编译报错
//现在假设上面这个不会报错
//现在塞一个数据
animalResult.setData(new Animal());
//那请问这里getData获取的是 animal 还是 dog 这变成了不确定的. 如果上面的编译不报错,那我们还可以setData任何一个 animal的子类, 那你在get的时候就根本 不知道这个取出来的对象到底是哪一个.
Dog dog = animalResult.getData();

所以为了安全考虑,java设置了限制符? extends X   ? super X

**2. 型变性通配符—- ? extends **

1
2
3
4
5
Result<Dog> dogResult = new Result<>(new Dog());
Result<? extends Animal> animalResult = dogResult;// 编译通过
// animalResult = new Result<Object>(new Object);// 编译报错
// animalResult.setData(new Animal());//编译报错
Animal animal = animalResult.getData();

? extends X指定了 泛型的上界,也就是 X 或者是 X 的子类. 所以我们在取数据的时候是可以进行的,因为数据一定是 X 类型的, 但是不允许你插入数据.比如你看 ArrayList.addAll方法:

1
2
3
4
5
class ArrayList{
// 指定了泛型上界是 E, 然后addAll只做取的操作,所以这是使用 ? extends 是非常好的
public boolean addAll(Collection<? extends E> c) {
}
}

3.逆变型通配符 —- ? super

1
2
3
4
5
6
Result<Dog> dogResult = new Result<>(new Dog());
Result<Object> objResult = new Result<>(new Object());
Result<? super Animal> animalResult = objResult;
//animalResult = dogResult;// 编译报错
animalResult.setData(new Dog());
Animal animal = animalResult.getData();

? super X规定了泛型下界X,必须是X或者是X的父类才行.

总结:

**? extends X ** :

  1. 限定了上界,泛型类型必须是 X 或者 X 的子类
  2. 此通配符只可以读,不可以写
  3. 对应的是Kotlinout

? super X:

  1. 限定了下界,泛型的类型是 X 或者是 的父类
  2. 此通配符可以写 但是读没法确定类型.
  3. 对应的是kotlinin

特别好的博客:地址