(1)是什么?
一种允许我们在不确定参数类型时候使用的类型。例如我不知道A方法应该会传String还是int,我就用个泛型先占坑。
(2)为什么要用泛型?
泛型可以在编译期自动确定具体类型,检查类型是否匹配,可以提高代码的重用率,减少冗余编码。
(3)泛型与Object的区别?
像上面说的我不知道方法A的参数类型,其实也可以使用Object,但是使用Object出参的时候返回的也是Object,导致范围非常广泛, 返回值也许是其它类型。就会在运行时得到一个类型转换异常(ClassCastException: XX can not be cast to XXX.class);使用泛型的话避免了Object的强转型问题,同时泛型在编译期会被擦除,转换成具体的类型,保证了类型安全性。
例如:
Public Object test(Object obj){}
Public T test( T t ){}
方法一调用时候必须强转型:User user = (User) XX.test( param );
方法二可以:User user = XX.test( param );
(4)什么是类型擦除?
JVM提供的针对数据类型的处理机制,编译阶段会把泛型转成对应的类型进行校验。
擦除规则是:
(1)如果泛型没有制定具体类型,默认使用Object做原始类型。
(2)如果泛型有继承关系限定类型,则拿父类做原始类型。
(3)如果有多层关系,例如A是B儿子,B又是C儿子,则拿A做原始类型。
类型擦除只会判断最外层的类型,对于内部嵌套的类型无法判断:
其实好理解,万一你对象里面还套个List之类的,深层嵌套其实对编译期是很难判断的
(5)怎么用?
// 定义泛型类
class Test <T>{
// 定义泛型参数
private T t;
// 定义泛型类的有参构造方法
public Test(T a) {
this.t = a;
}
public void say1(){
System.out.println(t);
}
public void say2(T x){
System.out.println(x);
}
// 这里使用的泛型是该静态方法自己声明的泛型
public static <E> E getTest(E e){
return e;
}
// 这里使用的泛型是类声明的泛型
public T getTest2(T e){
return e;
}
}
直接写一个main,调用:
public static void main(String[] args) throws Exception {
String a = "hellow";
Test test = new Test(a);
test.say1();
test.say2(123);
Object obj = test.getTest2("你好吗jojo");
System.out.println(obj);
Object obj1 = test.getTest2(11111);
System.out.println(obj1);
}
查看结果:
注意!
(1)静态泛型方法在返回值前加上来表示泛型变量,因为静态方法不依赖类的初始化,如果不自己声明泛型变量会编译出错!
(2)泛型方法定义要在返回值类型前面加
public <C> void say2(C x){
System.out.println(x);
}