JS Bin

集合泛型的不变性,而数组具有协变性,注意赋值容易导致的出错

@大神爱吃茶

 

  泛型的实际应用情况和通配符的使用,关于大范围和小范围互相赋值的时候JVM编译报错的问题:

问题描述:继承关系

class A {}
class B extends A {}
class C extends A {}
class D extends B {}

下面给出了几种说法:

The type List<A>is assignable to List.

The type List<B>is assignable to List<A>.

The type List<Object>is assignable to List<?>.

The type List<D>is assignable to List<?extends B>.

The type List<?extends A>is assignable to List<A>.

The type List<Object>is assignable to any List reference.

The type List<?extends B>is assignable to List<?extends A>.

(1)首先谈泛型只是在编译期保证对象类型相同的技术,比如在指定的类中声明了一个泛型,那么表示在此类中某一个属性的类应该是声明的这种类型的,而真正在代码运行的时候JVM会查出来泛型的存在。

(2)Java数组具有协变性、集合不具备协变特性

function(Person person);

  对于上面这个函数,如果我传入的是一个Student student对象的话,编译期是不会报错的,这是多态的特性。

function(Person[] person);

  而对于上面的这个函数如果我传入的是一个Student[] student数组进去的话,编译期也不会报错,这是数组的协变性。

public class TestConvert {

	public static void main(String[] args) {
		Student[] students = new Student[10];
		System.out.println(TestConvert.function(students));
	}

	public static int function(Person[] persons) {
		return 1;
	}
}

  

 

 

 

(3)但是如果我的函数是这样的:我想要传进去一个List<Student> students的话,编译器就会报错,这就是集合的泛型不变性,这点与数组的协变性不同。

function(List<Person> persons);

  我们可以将泛型改成这样 function (List <? extends Person> ),这样之后,当我们再传入一个List <Student>  students集合进去,编译器就就不会报错了。也就是说可以传入包含Person的子类的List了。也就是引进了通配符的使用。

注:<? extends A> 代表小于等于A的范围<? super A>代表大于等于A的范围<?>代表全部范围

  换一句话说List<A>和List<B>的集合对象不能直接来赋值的,而只有是一个范围的情况才可以被赋值进去,比如List<? extends A>这个就代表的是一个大的范围,可以将其子类的集合对象List<B>放进去。

 

 

posted @ 2019-12-03 10:46  左五六  阅读(416)  评论(0编辑  收藏  举报