泛型的基本概念和基本形态
泛型基本概念
泛型
,即参数化类型。这里的类型指的是类或者接口,参数化,就是说这个类或者接口允许附带一些其他信息对这个类或者接口的实际使用产生了约束作用。
原生态类型和类型参数
在 Java 1.5 出现之前,泛型是不存在的,我们把那个时候的类或者接口具备的形态称为原生态类型
。也就是说,如果你使用的 jdk 版本是1.5之前的,你看到的类或者接口就会是原生态类型,如果你翻看jdk原码,比如jdk 1.8,查看List接口,你会发现 List< E >,这里 List< E >就是泛型,List 就是原生态类型。如果你自己写了一个普通的 POJO,其就是原生态类型,一旦你在他的定义上加上了< E >等类型参数
,那么这个 POJO 就从原生态类型
变身为泛型
了。
定义一个泛型需要原生态类型和类型参数,即
原生态类型 <类型参数>
就是泛型。需要注意的是,类型参数不能是Java 基本类型,因为类型参数必须是可以对象化的,这意味着可以使用基本类型对应的包装类型。
泛型及相关的一些类型
泛型的应用是基于泛型的定义的,由于泛型的出现,Java 世界一下子出现了很多形式多样的类型形态,他们分别在类或接口的定义,泛型方法的定义,泛型的声明中出现,在规则上有细微的不同,下面进行列举。(内容参考了 《Effective Java 第2版 第23条》)
常规形态
自己写了一个类
DemoName
和一个接口DemoInterface
来说明
如果我们把各种形态的出现分类的话,可以分为 泛型类或接口的定义、泛型方法的定义、泛型类型的声明,但是对于原生态类型的应用场景,我们不再做显示的声明。
原生态类型
DemoName/DemoInterface 。可以用在类或接口的定义和声明、方法的定义
public class DemoName{
}
public interface DemoInterface {
}
实际类型参数
任何一个原生态类型,比如 DemoName,但是是具体的。可用于类/接口的定义、声明,泛型方法的定义与使用。形式类型参数
任何一个原生态类型,但是是非具体的,比如 E ,只能用于泛型 类型/接口/方法的声明。泛型
DemoName< E >、DemoName< E,K>,用于类或者接口的定义,E 表示无限定的参数化类型,具体实例化传入内容要根据类的功能需要进行。
public class DemoName<E,K> {
}
public class DemoName<E> {
}
public interface DemoInterface<E,K> {
}
public interface DemoInterface<E> {
}
参数化类型
泛型是需要实例化的,比如List< String>,比如 DemoName< String>。可以用于泛型类/接口的定义和声明、泛型方法的定义。
public class DemoName<String>{
public void test(){
DemoName<String> demoName=new DemoName<String>();
}
public DemoName<String> test2(){
return new DemoName<String>();
}
}
泛型方法
public static < E> List< E> test(E[] a)
public class DemoName{
//泛型方法所在的类未必是泛型的哦
public static <E> List<E> test(E[] a){
List<E> list=new ArrayList<E>();
for(int i=0;i<a.length;i++){
list.add(a[i]);
}
return list;
}
}
类型令牌
DemoName.class
非常规形态
由于泛型是编译器检查类型合法性,那么我们只能在定义的时候指定具体的类型或者 T 吗?这样就显得太不方便了,有时候我们需要指定一个范围,比如只能是Integer或者其父类等作为实际类型参数,笔者把这部分放到下一篇文章去了。那种形态样子的一个例子 < E extends Number>