JDK1.5版本以后出现的新特性,用于解决安全问题,是一个类型安全机制。
好处:
1,将运行时期出现问题ClassCastException 异常 转移到了编译时期
方便于程序员解决问题,让运行时间问题减少,安全
2,避免了在重写比较器时的强制转换麻烦
泛型格式:
通过 < > 来定义要操作的引用数据类型。
泛型的限定:
? 通配符,也可以理解为占位符。
? extends E 可以接收 E 及其子类。 称上限。
? super E 可以接收 E 及其父类。 称下限。
注意:像这种 ArrayList <Person> al3 = new ArrayList <Student> ();
泛型里两边不一样是不是行的。必须是要一样的,子父类也不行。
泛型里的类型必须是引用类型,不能是基本数据类型,否则报错。
例:
public void method4(ArrayList < ? extends Person > al) //此方法只能接收Person及其子类
{
Iterator < ? extends Person> it = al.iterator(); //迭代的时候也要加上泛型
while (it.hasNext())
{
System.out.println(it.next().getName());
}
}
public void method3(ArrayList< ? super Student> al) //此方法能接收Student及其父类
{
Iterator< ? super Student> it = al.iterator();
while (it.hasNext())
{
System.out.println(it.next());
}
}
public < T > void method2(ArrayList< T > al) //此方法可以适用于所有类型的ArrayList集合
{
Iterator < T > it = al.iterator();
while (it.hasNext())
{
T t = it.next(); //好处是可以在此处控制
System.out.println(t);
}
}
public void method(ArrayList< ? > al) //此方法可以适用于所有ArrayList类型的集合
{
Iterator < ? > it = al.iterator();
while (it.hasNext())
{
System.out.println(it.next());
}
}
在使用java提供的对象时,什么时候写泛型呢?
通常在集合框架中很常见,只要见到 < > 就要定义泛型。
当使用集合时,将集合中要存储的数据类型作为参数传递到 < > 中即可。
其实 < > 就是用来接收类型的。
泛型类
泛型类定义的泛型,在整个类中有效,
如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了
为了让方法可以操作不同类型,可以将泛型定义在方法上
特殊之处:
静态方法不可以访问类上定义的泛型。
如果想让静态方法操作不确定的应用数据类型,可以将泛型定义在静态方法上。
例 :
class Demo < T >
{
public void show( T t)
{
System.out.println("show:"+t);
}
public < T > void print( T t)
{
System.out.println("print:"+t);
}
public static < T > void method( T t) //注意:泛型放在返回类型前面
{
System.out.println("static :"+t);
}
}
建立对象如:Demo<String> d = new Demo<String>();
泛型定义在接口上
例:
// 1,类实现泛型接口
interface Inter < T >
{
void show( T t);
}
class Inter2 implements Inter <String> //在实现该接口的时候指明类型
{
public void show(String s)
{
System.out.println("show:"+s);
}
}
// 建立对象
Inter2 i2 = new Inter2();
// 2,泛型类实现泛型接口
class InterImpl < T > implements Inter < T >
{
public void show( T t)
{
System.out.println("InterImp<>+show:"+t);
}
}
// 建立对象
InterImpl < Integer > al = new InterImpl < Integer > ();
// 输出该集合元素
Iterator < Integer > it = al.iterator(); //迭代器也要带上泛型
while (it.hasNext())
{
System.out.println(it.next().getName());
}
通过反射来获取泛型的实际类型
如:Vector < Date > v1 = new Vector < Date >();
怎么拿到Date这个实际类型呢?
把它转换成方法的参数就可以拿到,因为在编译的时候会去泛型化。
注意:
public void apply( Vector < Date > v1) { }
public void apply( Vector < String > v1) { }
这两种方法不是重载,编译不通过,因为它们是同一方法。因为会去泛型化,编译会去掉泛 型的限定
所以通过这点,我们就可以通过方法来获取泛型实际类型。
例:
class Text{
public void apply( Vector < Date > v1) { }
//通过字节码拿到方法
Method applyMethod = Text.class.getMethod(“apply” , Vector.class );
//通过方法返回方法的形参类型保存至数组中
Type [] types = applyMethod.getParameterTypes();
//参数化类型,因为参数只有一个,我们取第一个元素即可。
ParameterizedType pType = (ParameterizedType)types[0];
//返回该参数的实际类型,因为参数类型也可能是多个(如:Map泛型有两个),所以这取第一个。
System.out.println( pType.getActualTypeArguments()[0] );
}