一、由来
1、 泛型从JDK1.5之后追加到Java语言里面的,其主要目的是为了解决ClassCastException的问题,在进行对象的向下转型时,永远都存在有安全隐患。可以编译,运行错误 解决大多部分
2、而泛型的本质在于,类中的属性或方法的参数与返回值可以由对象实例化的时候动态决定。
回避掉对象的强制转换
二、基础
1、Point 这个T表示派生自Object类的任何类 一般大写字母
优点 1、Object 要强制转换 泛型不用 2、传入类型不对,编译时会报错
常用元素表示:
class MorePoint<T,U,A,B,C>{ }
- E — Element,常用在java Collection里,如:List,Iterator,Set
- K,V — Key,Value,代表Map的键值对
- N — Number,数字
- T — Type,类型,如String,Integer等等
2、?与 T
T的作用是限制泛型可用类型,泛型类的类型必须实现或继承了anyClass这个接口或类,无论anyClass是接口还是类.
?是类型通配符,其主要作用是创建一个泛型类对象时限制这个泛型类的类型实现或继承继承某个接口或类的子类.
·?extends 类:设置泛型上限;|-例如:"? extends Number":表示该泛型类型只允许设置Number或者Number的子类
·? super 类: 设置泛型的下限: |-例如:"? super String":只能够使用String或其父类。
3、其他问题
interface IPoint<S>{
public String print(S s) ;
}
class PointImpl implements IPoint<T> // 错误 T 不能单独出现在接口中
class PointImpl implements IPoint<String> //正确
class PointImpl<T> implements IPoint<T> //子类中接口方法与IPoint<T> T类型一致
class InfoImpl<T,K,U> implements Info<U> //泛型类
public static <T>list<T> aslist(T...a) //<T> 表示泛型方法 T 表示泛型类型
public static <T> void StaticMethod(T a)
//
public class StaticFans {
//静态函数
public static <T> void StaticMethod(T a){
Log.d("harvic","StaticMethod: "+a.toString());
}
//普通函数
public <T> void OtherMethod(T a){
Log.d("harvic","OtherMethod: "+a.toString());
}
}
//静态方法
StaticFans.StaticMethod("adfdsa");//使用方法一 必须是派生自Object类的类型 隐式
StaticFans.<String>StaticMethod("adfdsa");//使用方法二
//常规方法
StaticFans staticFans = new StaticFans();
staticFans.OtherMethod(new Integer(123));//使用方法一
staticFans.<Integer>OtherMethod(new Integer(123));//使用方法二
4、 <T> T 与Class <?> clazz
< T > 表示传入的类型 T表示返回类型(比如String、int)
Class 传递类的class对象,传入类型 (T aa)
关于的进一步说明(参考自)
按理说有一个T表示返回值就可以了,为什么还要一个呢?这个表示这个方法声明为泛型方法.
但是又有一种情况出现了,同样是泛型方法,为什么下面的getName方法就不用声明呢?
public class Test1<T> {
private T name;
public T getName(T name){
return name;
}
public static <T> void printA(T a){
System.out.println(a);
}
}
解释:对于声明了的类(Test1就是声明了的类)不需要声明泛型方法,对于带了static的方法,它并不属于类的一部分,所以相当于没有声明的类,所以需要声明为泛型方法.
像Test2这样的类就必须声明泛型方法
public class Test2 {
public <T> T test1(T A){
System.out.println(A);
System.out.println(A.getClass());
return A;
}
}
三、泛型擦除
过程:检查代码中泛型的类型(引用),然后再进行类型擦除,在进行编译的。
运行时可以设置任意类型,不受类型限制,例如:
打印:
因为类型擦除的问题,所以所有的泛型类型变量最后都会被替换为原始类型。这样就引起了一个问题,既然都被替换为原始类型,那么为什么我们在获取的时候,不需要进行强制类型转换呢?
自动类型转换
看下ArrayList和get方法:
public E get(int index) {
RangeCheck(index);
return (E) elementData[index];
}
看以看到,在return之前,会根据泛型变量进行强转。
编译时泛型擦除 原始类型 最小父类型 知道Object
泛型类中的静态方法和静态变量不可以使用泛型类所声明的泛型类型参数
所以,虚拟机巧妙的使用了桥方法,来解决了类型擦除和多态的冲突。
泛型的类型参数不能用在Java
异常处理的catch
语句中。 分不清异常
原始类型List和带参数类型List<Object>
之间的主要区别是,在编译时编译器不会对原始类型进行类型安全检查,却会对带参数的类型进行检查。