为什么要有泛型(Generic)
所谓泛型,就是允许在定义类接口时通过一个标识表示类中某个属性的类型或是某个方法的返回值及参数类型。这个类型参数将在使用时确定。
使用前后的对比:
在集合中使用泛型之前的情况:
①类型不安全(可能混入其他类型的数据)。
②强转时,可能出现转换异常(classCastException)。
在集合中使用泛型之后的情况:
①在编译时,会进行类型检查,保证数据安全。
②避免了强转。
限制容器放入的类型
class A<E>{
boolean add (Ee);
}
总结:
①集合接口或集合类在jdk5.0时都修改为带泛型的结构。
②在实例化集合类时,可以指明具体的泛型类型。
③指明完以后,使用到类的泛型的位置,必须为指定的类型。
④泛型的类型必须是类,不能是基本数据类型,但可以是包装类。
⑤默认泛型为Object。
如何自定义泛型结构(类、接口;方法)
泛型类,接口:
定义在方法名,接口名后,用 < > 包裹。
建议:如果定义了类是带泛型的,在实例化时要指明类的泛型。
由于子类继承带泛型的父类时,指明了泛型,子类实例化时不再需要指明
例:
public class A<T> extends B<T>{} //是泛型类
public class A extends B<T>{} //不是泛型类
静态方法中不能用泛型(具体为类的泛型),异常类不能声明为泛型类。
.T[ ] ar r= (T[ ]) new Object [10];
泛型方法:
在方法中出现了泛型结构,泛型参数与类没关系。
例:
public List<E> copyFrom ArrayToList (E[] arr){} //错的
public<E> List <E> copyFromArrayToList (E[] arr){} //对的
1、泛型方法在调用时,指明泛型参数的类型。
2、泛型方法可以声明为静态的,
原因:泛型参数是在调用时确定的,并非实例作类时确定。
例:
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)
使用时指定的类型不能小于操作的类,即>=。