文章目录
1.背景
由上图可知,泛型主要解决两种情况
1.解决元素存储的安全性问题
2.解决获取数据元素时,需要类型强转的问题
2.概念
所谓泛型:就是允许在定义类、接口时指定类型形参,这个类型形参将在声明变量、创建对象时确定(即传入实际的类型参数,也可称为类型实参)。JDK15改写了集合框架中的全部接口和类,为这些接口、类增加了泛型支持,从而可以在声明集合变量、创建集合对象时传入类型实参,这就是前面程序看到 List和 ArrayList两种类型。
泛型的实质:允许在定义接口、类时指定类型形参,类型形参在整个接口、类体内中可当成类型使用,几乎所有可使用其他普通类型的地方都可以使用这种类型形参
泛型主要有 泛型类、泛型接口、泛型方法
,其中泛型类和泛型接口其实泛型使用都是一样的,唯一区别就是类与接口的区别,而泛型方法,和泛型类没啥关联关系,任何一个类里都可以定义泛型方法,因为在调用泛型方法的时候,就可以指定具体类参数
2.1 泛型类
2.1.1自定义泛型类
2.2.2 注意
1.若对象实例化时不指定泛型,默认为:Object
2.泛型不同的引用不能相互赋值
3.加入集合中的对象类型必须与指定的泛型类型一致
4.静态方法中不能使用类的泛型
5.如果泛型类是一个接口或抽象类,则不可创建泛型类的对象
6.不能再catch中使用泛型
7.从泛型类派生子类,泛型类型需具体化
类,接口中的类型参数,只有在定义类、接口时才可以使用类型形参,当使用类、接口时应为类型形参传入实际的类型
上面为true,实际上系统并没有为ArrayList和ArrayList生成新的class文件,不会把这两个当做新的类来处理,所以不管泛型类型参数是什么,他们在运行时总有同样的类
2.2.3 不能使用泛型类
类的静态变量和方法在所有的实例间共享,所以在静态方法、静态初始化或者静态变量的声明和初始化中不允许使用类型形参
由于系统中并不会真正生成泛型类,所以instanceof运算符后面不能使用泛型类
2.2 泛型和继承
这里可以这样理解,如下图所示,泛型是ArrayList< Object> object,那么传递给这个object变量的值也应该是满足元素是Object类型的集合,而integer里的元素类型指定是Integer,所以不应该把集合元素类型为Integer的再赋值给需要集合类型是Object的变量
但是如果是B
数组是可以这样A[] = B[]
2.3 泛型方法
方法,也可以被泛型化,不管此时定义在其中的类是不是泛型化的。在泛型方法中可以定义泛型参数,此时,参数的类型就
是传入数据的类型
静态方法不可以使用泛型类型,但静态方法也可以被泛型化,定义泛型方法时,必须在返回值前边加一个,来声明这是一个泛型方法,持有一个泛型T,然后才可以用泛型T作为方法的返回值。
泛型静态方法内(有标识)可以使用泛型类
优化
2.4 通配符
在“泛型和继承”上,可以看出G< A>和G< B>是不能直接赋值的,即使它们存在父子关系,那么这个时候就要用到通配符了
通配符用?表示
由上图可知,若list<?>里不指定参数类型,那么就不能随意往该所指向的集合里添加元素
注意:有<?>表示的变量,比如Collection<?> c ,是不能进行插入操作的,只能够进行读取操作
最后强调,通配符主要是用来引用我们传递的集合的,而不是通过它向集合去插元素的!!!
2.4.1 通配符上限和下限
指定类型参数上下限的好处在于我们通过通配符引用任何元素的时候,可以很方便调用各个元素的方法而无需去判断类型再强制转换
多个上限情况
1.可以使用List<? extends person>指向List、List、List。只要元素类型为Person,或其子类就是可以的。
2.可以使用List<? super student>指向List、List、List。只要元素类型为Student或Student父类就是可以的。
3.注意:不能再new时使用通配符。
new ArrayLsit<? extends person>(),这是不可以的!
4.可以在定义引用时使用通配符:
ArrayList<? extends Person>list;
2.4.2 泛型方法和类型通配符的区别
注意上面的E是类的类型参数,而T是方法的类型参数