为什么要有泛型(Generic)
所谓泛型,就是允许在定义类或接口时通过一个标识表示类中某个属性的类型或是某个方法的返回值及参数类型。这个类型参数将在使用时确定。
在集合中使用泛型之前的情况:
①类型不安全(可能混入其他类型的数据)。
②强转时,可能出现转换异常(classCastException)。
在集合中使用泛型之后的情况:
①在编译时,会进行类型检查,保证数据类型的安全。
②避免了强转,提高效率。
使用:
class A<E>{ //编译时指定E的类型,运行时所有的E都会替换为指定类型
E e; //e可以是指定的类型
public A(E e){ //限制容构造器中放入的类型为E
this.e=e;
}
punlic E f(){ //返回一个E类型的结果
return s;
}
}
总结:
①集合接口或集合类在jdk5.0时都修改为带泛型的结构。
②在实例化集合类时,可以指明具体的泛型类型。
③指明完以后,使用到类的泛型的位置,必须为指定的类型。
④泛型的类型必须是类,不能是基本数据类型,但可以是包装类。
⑤默认泛型为Object。
如何自定义泛型结构(类、接口;方法)
泛型类,接口:
定义在类名,接口名后,加上 < 类型 > (这里的类型为引用类型,不能是基本数据类型)。
class 类名<E>{} //泛型类
interface 方法名<E>{} //泛型接口
建议:如果定义了类是带泛型的,在实例化时最好要指明类的泛型。
由于子类继承带泛型的父类时,父类已经指明了泛型,子类实例化时不再需要指明。
子类继承带泛型的父类,子类不一定是泛型类,即泛型不具有继承性。例:
public class A<T> extends B<T>{} //A是泛型类
public class A extends B<T>{} //A不是泛型类
注意:静态方法中不能使用类的泛型,因为泛型类的类型,是在创建对象的时候确定的(创建时指定,默认是Object),静态方法在未创建对象时就已存在。
异常类不能声明为泛型类,使用泛型的数组不能初始化(不能确定类型)。
泛型方法:
语法:权限修饰符 <E> 返回类型 方法名(参数){}
public String<E> sayHello(String text){}
在方法中出现了泛型结构,泛型参数与类没关系(参数的泛型为方法指定的泛型)。
泛型方法在调用时,必需指明泛型参数的类型(直接传入参数会根据传入的参数确定泛型类型)。
泛型方法可以声明为静态的,使用自己的泛型。
原因:泛型参数是在调用时确定的,并非实例作类时确定。例:
public static <E> List <E> alist (E[] e){}; //E与类的泛型没有关系
泛型在继承方面的体现:
①类A是类B的父类,但G<A>和G<B>二者不具备子父类关系,二者是并列关系。
②类A是类B的父类(接口),A<G>和B<G>具有子父类关系,A <G>为B<G>的父类。
通配符的使用
通配符:? <?> (可以约束传入的泛型类型)
G<?>是G<A>和G<B>公共的父类
1.添加(写入)
对于List<?>就不能向其内部添加数据,除null以外。
2、获取(读取):
允许读取数据,读取的数据类型为Object
有限制条件的通配符的使用:
1、< ? extends Number>(无穷小,Number)
只允许泛型为Number及Number子类的引用调用。
2、< ? super Number> (Number,无穷大)
只允许泛型为Number及Number父类的引用调用。
3、< ? extends comparable>
只允许泛型为实现Comparable接口的实现类的引用调用.
通配符指定上限:extends
使用时指定的类型必须继承某个类,或实现某个接口,即<=。
通配符指定下限:super
使用时指定的类型不能小于操作的类,即>=。