在JDK1.5之后,Java通过泛型解决了类型安全的问题,泛型的本质就是参数化的类型,也就是将所操作的数据类型作为参数。
使用泛型能够写出更加灵活通用的代码。
泛型将对代码的安全性检查从运行期提前到了编译期。
泛型能够省去强制类型转换【由于编译期已经知道了准确的类型,因此在编译期会进行强制的类型转换,不用自己转换】
泛型类:
泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。最典型的就是各种容器类,如:List、Set、Map。
泛型类实例:
//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
//在实例化泛型类时,必须指定T的具体类型
public class Generic<T>{
//key这个成员变量的类型为T,T的类型由外部指定
private T key;
public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定
this.key = key;
}
public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定
return key;
}
}
泛型方法:
在java中,泛型类的定义非常简单,但是泛型方法就比较复杂了。
尤其是我们见到的大多数泛型类中的成员方法也都使用了泛型,有的甚至泛型类中也包含着泛型方法,这样在初学者中非常容易将泛型方法理解错了。
泛型类,是在实例化类的时候指明泛型的具体类型;泛型方法,是在调用方法的时候指明泛型的具体类型 。
/**
* 泛型方法的基本介绍
* @param tClass 传入的泛型实参
* @return T 返回值为T类型
* 说明:
* 1)public 与 返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。
* 2)只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
* 3)<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
* 4)与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。
*/
public <T> T genericMethod(Class<T> tClass)throws InstantiationException ,
IllegalAccessException{
T instance = tClass.newInstance();
return instance;
}
泛型接口:
//定义一个泛型接口
public interface Generator<T> {
public T next();
}
常用的表示: < E > 、 < T> 、 < K > 、 < V>
泛型通配符:<?> 能代表任何类型
泛型只存在于代码编译阶段,在进入JVM之前,与泛型相关的信息会被擦除掉,专业术语上也叫类型擦除。
这里有一道经典的测试题:
List<String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();
System.out.println(l1.getClass() == l2.getClass());
结果为true 在编译结束后在JVM中都会变成List.class
如果泛型参数无界,那么编译器会将其替换为Object.
如果泛型参数有界,那么编译器会将其替换为边界类型
public class TypeErasureDemo {
public <T> void forEach(Collection<T> collection) {} //1
public <E extends String> void iter(Collection<E> collection) {} //2
}
如1 处代码,编译期会将其泛型替换为了Object,2处代码中编译期将泛型替换为了String
作者:龙马要一直变强啊