什么是泛型
泛型是一种把明确类型的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,而这种参数类型可以用在类、方法和接口中,分别被称为泛型类、泛型方法、泛型接口。
为什么要用泛型
- 避免了类型强转的麻烦。
- 它提供了编译期的类型安全,确保在泛型类型(通常为泛型集合)上只能使用正确类型的对象,避免了在运行时出现ClassCastException。
- 编译时检查添加元素的类型,提高了安全性
泛型在jdk7前后的区别
jdk7之前
需要在等号后面指定使用的具体类型
HashMap<ElemType> hash=new HashMap<ElemType>()
jdk7之后
不需要在等号后面指定使用的具体类型,有类型自动推断。最典型的就是各种集合框架容器类,如:List、Set、Map。
Map<ElemType> hash=new HashMap<>()
泛型类
用在类的定义中的泛型类型,称为泛型类。
格式 修饰符 class 类名<代表泛型的变量> { }
自定义泛型的细节:
- 普通成员可以使用泛型
- 使用泛型的数组不能初始化
- 静态方法中不能使用类的泛型
- 泛型类的类型,是在创建对象时确定
- 如果在创建对象时,没有指定类型,默认为Object
//自定义泛型类,在创建对象的时候确定泛型的具体类型
public class Order<T>{String name;
int age;
T orderT;
public Order(){}
public Order(String name,int age,T orderT){
this.name=name;
this.age=age;
this.orderT=orderT;
}
}
泛型接口
泛型接口与泛型类的定义及使用基本相同。
格式 修饰符 interface接口名<代表泛型的变量> { }
//举例
public interface Example<T> {
public abstract void add(T t);
}
//泛型接口的使用
//1.在实现时声明泛型的具体类型
public class ExampleImpl implements Example<String> {
@Override
public void add(String s) {
System.out.println("设置了泛型为String类型");
}
}
//2.在实现中也不声明具体类型,知道实例化类的时候才声明
public class ExampleImpl <T> implements Example<T> {
@Override
public void add(T t) {
System.out.println("没有设置类型");
}
}
泛型方法
在调用方法时才明确泛型的具体类型。
格式 修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ }
//注意:泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系。
public class Order<T>{
//copyFromArrayToList()就是泛型方法
public <E> List<E> copyFromArrayToList(E[] arr){
}
}
泛型里的通配符
在泛型中“?”是一个通配符,一般是不知道使用什么类型来接收的时候使用。
通配符的使用:
ArrayList<?> list=new ArrayList<>();
//list.add(2); 当使用通配符后,不能添加除null之外的任何值
list.add(null);
通配符实现指定一个泛型的上限和下限
格式:
上限: <? extends ElemType>,也就表示只能接收ElemType类型及其子类
下限: <? super ElemType>,也就表示只能接收ElemType类型及其父类
class A{}
class B extends A{}
class C extends B{}
//下面是调用
//上限
//ArrayList<? extends B> list=new ArrayList<A>();会报错
ArrayList<? extends B> list1=new ArrayList<B>();
ArrayList<? extends B> list2=new ArrayList<C>();
//下限
//ArrayList<? extends B> list=new ArrayList<C>();会报错
ArrayList<? super B> list3=new ArrayList<B>();
ArrayList<? super B> list4=new ArrayList<A>();
泛型的继承
class A{}
class B extends A{}
class G<T>{}
//虽然B继承于A,但不能说G(B)继承于G(A) ,可以说G(A)和G(B)具有共同的父类G(?)
//但可以说B(G)继承于A(G)
泛型使用的注意事项
- 不可以在静态方法中使用类的泛型
- 异常类不可以是泛型的
- 不能使用new E[],但是可以使用E[] elemnets=(E[])new Object[capacity]
- 父类有泛型,子类可以选择保留泛型或者指定泛型类型,子类也可以添加自己的泛型
- 泛型只能是引用类型
- 在给泛型指定具体类型后,可以传入该类型或其子类类型
- 在不明确泛型的具体类型时,默认的类型时Object
- 泛型不同的引用不能相互赋值