泛型
1.概念
泛型(generics/type parameter)是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
2.出现原因
类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,编译可以通过,但是在运行的时候才出现异常,这是一个安全隐患。
3.设计原则
只要编译时时没有出现警告,运行时期就不会出现ClassCastException异常
4.使用规范
1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
3、泛型的类型参数可以有多个。
4. 泛型无法向上转型。
5.使用范围
(1).泛型类
泛型定义在类上,在类的方法中也可是使用。如下:
public class Foo<K,T,V> {
K k;
T t;
public Foo() {
}
public Foo(K k, T t, V v) {
this.k = k;
this.t = t;
this.v = v;
}
V v;
public K getK() {
return k;
}
public void setK(K k) {
this.k = k;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public V getV() {
return v;
}
public void setV(V v) {
this.v = v;
}
public void showType(){
System.out.println(this.k.getClass().getName()+"\t"+
this.t.getClass().getName()+"\t"+
this.v.getClass().getName());
}
//测试代码
public static void main(String[] args) {
Foo<Integer,Double,String> foo1 = new Foo<>(12,12.5,"aa");
foo1.showType();
Person p1 = new Person(1,"权限");
Foo<Integer,Double, Person> foo2 = new Foo<>(12,12.5,p1);
foo2.showType();
Foo<Integer,Double,String> foo3 = new Foo<>(new Integer(121),12.5,"aa");
foo3.showType();
}
}
(2)泛型接口
泛型接口,当未传入泛型泛型实参时,需要在类中加入反省的声明。
若传入了泛型实参,则使用的地方都将换成泛型实参。如下展示:
泛型接口
public interface Oper<T> {
void add(T t);
void del(T t);
void upad(T t);
List<T> queryAll(T t);
}
未传入实参
import java.util.List;
public class OperImpl<T> implements Oper<T> {
@Override
public void add(T t) {
}
@Override
public void del(T t) {
}
@Override
public void upad(T t) {
}
@Override
public List<T> queryAll(T t) {
return null;
}
}
传入实参
public class StringImp implements Oper<String> {
@Override
public void add(String s) {
}
@Override
public void del(String s) {
}
@Override
public void upad(String s) {
}
@Override
public List<String> queryAll(String s) {
return null;
}
}
(3)泛型方法
注意:
泛型类中使用了泛型的成员方法并不是泛型方法。
只有声明了的方法才是泛型方法。
若要在静态方法上使用泛型,必须将静态方法也定义成泛型方法。
如下展示一个泛型方法和可变参数的例子:
public class Foo3 {
public Person getPerson(){
return new Person();
}
public <T>T getT(T t){
System.out.println(t);
return t;
}
/**
*
* @param t
* @param <T>返回泛型数组
*/
public <T> void getT(T... t){
if(t!=null){
for (T t1:t
) {
System.out.println(t1);
}
}
System.out.println(t);
}
public static void main(String[] args) {
Foo3 foo3 = new Foo3();
/* foo3.getT(1);
foo3.getT(true);
foo3.getT(12.5f);
foo3.getT("哈哈");*/
foo3.getT(3,45,657,79);
foo3.getT(13,true,"aa");
}
}
(3)泛型通配符
泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName(“java.lang.String”)
* <T extends Collection>这么定义类型的时候,
* 就限定了构造此类实例的时候T是确定的一个类型,
* 这个类型实现了Collection接口,
* 但是实现 Collection接口的类很多很多,
* 如果针对每一种都要写出具体的子类类型---通配符?
“?”代表未知类型
****注意在调用的时候
1、如果只指定了<?>,而没有extends,则默认是允许Object及其下的任何Java类了。也就是任意类。
2、通配符泛型不单可以向下限制,如<? extends Collection>,还可以向上限制,如<? super Double>,表示类型只能接受Double及其上层父类类型,如Number、Object类型的实例。
3、泛型类定义可以有多个泛型参数,中间用逗号隔开,还可以定义泛型接口,泛型方法。这些都与泛型类中泛型的使用规则类似。
4 泛型方法是否拥有泛型方法,与其所在的类是否泛型没有关系。要定义泛型方法,只需将泛型参数列表置于返回值前。
如下展示:
public class Foo2 <Collection > {
public static void main(String[] args) {
Foo2<? extends List> foo2 = new Foo2<List>();
Foo2<? extends List> foo21 = new Foo2<ArrayList>();
//<? super Double>
Foo2<? super Stack> foo22 = new Foo2<Vector>();
// Foo2<? super Stack> foo22 = new Foo2<Set>();
}
}