泛型
泛型指在一种未知的数据类型,只有在类被创建对象或者调用的时候才会明确相应的数据类型,也就是相当于把明确数据类型的任务推延到创建该类对象或者是调用方法的时候。
注意:在泛型使用的时候,<>中的数据类型必须为引用类型。
例如:
// An highlighted block
ArrayList<String> arr = new ArrayList<>();
在集合ArrayList < E >中E(element)便代表着一种泛型,只有当它被创建实例对象的时候,数据类型才会被确定(String),
为什么需要泛型
不使用泛型直接使用集合进行存储,由于集合对所存储的元素没有类型的限制,在数据进入集合之后,会被其默认为Object类型,可以存储任意类型的数据。那么在需要进行向下转型的时候,很容易出现ClassCastException(类型转换异常),例如:我可以将DOG和CAT类型的数据装在同一个Collection中,而在Collection则将其认为都是Object类型的数据,当我们想要使用DOG类所特有的方法时,就不能简单使用多态,必须进行向下转型将Object装为DOG,而这时就会将CAT转为DOG出现ClassCastException(类型转换异常)。泛型的存在就是要约束进入集合中数据的类型,避免出现类型转换异常。
使用泛型的好处
1.代码更加简洁,避免了相应的向下转型。
2.避免了*ClassCastException(类型转换异常)*出现,将运行期异常提升到编译期异常。
3.增加了代码的可读性及稳定性,限定了数据类型。
注意:泛型是什么类型就只能存储相应类型的数据
泛型的使用:
泛型是一个未知的数据类型,当不知道该使用什么数据类型的时候可以使用泛型。泛型可以接受任意数据类型。
泛型类
定义格式:
修饰符 class 类名 <代表泛型的变量> { }
例如:
public class last<E> {
private E name;
public E getName() {
return name;
}
public void setName(E name) {
this.name = name;
}
}//创建泛型类的时候,在所有需要确定数据类型的地方使用泛型进行代替。
泛型方法
定义格式:
修饰符<代表泛型的变量> 返回值类型 方法名(参数列表(使用泛型)) { }
public<T> void method(T t){
System.out.println(t);
}
}
在调用方法的时候确定泛型的数据类型
`
泛型通配符
当时用泛型类的时候,传递的数据中泛型类别不确定的时候,可以用通配符<?>表示,但是一旦使用泛型的通配符之后,只能使用Object类中的共性方法,集合自身方法无法使用
不能创建对象使用,只能作为方法的参数使用
注:泛型没有继承关系
//定义一个方法,能遍历所有类型的ArrayList集合
public static void printArray(ArrayList<?> list){
//使用迭代器遍历
Iterator<?> i = list.iterator;
while(it.hasNext()){
Object t = it.next();
System.out.print(t);
}
}
受限泛型
泛型的上限
格式:类型名称 <? extends 类> 对象名
意义:只接收该类型及其子类
泛型的下限
格式:类型名称 <? super 类> 对象名
意义:只接收该类型及其父类
注意:ArrayList< Integer >直观上是ArrayList< Number >的子类,但实际上并不是这样的,也就是说无法直接将ArrayList< Integer >中的值直接复制给ArrayList< Number >,如果想要这样做的话,需要使用泛型的上限这一定义,如:
@Test
public void f(){
ArrayList<Number> b = new ArrayList<>();
ArrayList<Integer> a = new ArrayList<>();
a.add(1);
a.add(2);
a.add(3);
a.add(4);
t(a,b);
out(b);
}
public <T> void t(List<? extends T> a, Collection<T> b){//这样的写法可以将两个泛型所可以接受的实际类型参数硬性卡在父类与子类的关系,因此,可以直接进行值的复制
for (T i:
a) {
b.add(i);
}
}
public <T> void out(Collection<T> a){
for (T i:
a) {
System.out.println(i);
}
}
泛型所对应的“泛型类”是在物理上是不存在的,因此在初始化或者类加载中是不会生成相应的class文件,因此,也不能在静态代码块、静态方法中使用泛型,如果需要在某个方法中使用泛型,就需要将该方法定义为泛型方法:修饰符 < T > 返回值类型 方法名 (形参列表)。
泛型方法与类型通配符
1.大多数时候泛型方法可以代替类型通配符
2.当通配符是用来支持灵活的子类化的时候就需要使用通配符
3.泛型方法允许泛型参数被用来表示方法的参数之间的依赖关系,或者返回值与参数之间的依赖关系,如果没有这种依赖关系就不能使用泛型方法
4.如果一个方法中的参数或者返回值(a)的类型依赖于参数(b)的类型,那么b的类型声明就不能使用类型通配符,如果b的类型无法确定,这种情况下就只能考虑泛型方法了。
学习笔记,欢迎指出错误。