jdk1.5之后出现的新特性:
泛型可以限定集合输入的类型,让编译器在编译的时候阻止非法输出的数据,从而使得编译器编译过程中不需要处理类型信息,提高编译效率。对于参数化的泛型类型,如getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其他类型的数据。例如用反射得到的集合,再通过add方法添加集合信息。
泛型是为编译器约束输入数据的,而通过反射式可以绕过编译器,所以反射得到的集合可以向泛型的集合里面添加各种有类型的数据。
例如:ArrayList<E> 中ArrayList称为原始类型,<>译为"typeof",ArrayList<E>称为泛型类型,E称为类型变量或者类型参数;
ArrayList<String>称为参数化的类型,String称为类型参数的实例或实际类型参数
参数化类型与原始类型全部兼容Vector v = new Vector<String>();或者:Vector<String> v = new Vector();都可以。
参数化类型不考虑类型参数的继承问题。也就是说泛型类型中的类型参数,等号两边只要不是同一种,那么编译就一定不会通过。
为什么在创建数组实例时,数组的元素不能使用参数化的类型?
编译器是严格按照步骤走的。它检测每一行代码的信息是否有误,但是不会用执行时候的答案来检测代码的正确性。
泛型限定:泛型的通配符(?)应用:?表示任意类型。比如当要定义一个任意参数化类型的集合(Collection<?> col),就用得到了通配符。
使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。比如集合中的add()方法,使用了?的集合就不能在调用这个方法。
public void printCollection(Collection<?> col){}
也就是说Collection<?> col = new ArrayList<String>();编译器让这个表达式被编译通过。
泛型的限定:?extends E:可以接收E类型或者E的子类。这是上限限定。?super E:可以接收E类型或者E的父类。这是下限限定
自定义泛型:
要定义一个泛型,必须在函数的返回值之前用尖括号括起来
1、//这样声明的泛型可以代替任意类型数据我们经常用到的键值对Map.Entry<K,V>不就是给予泛型的吗
KV都可以代替任意类型的值,但是在java中泛型的实际类型必须是引用类型<K,V> void get(K k,V v){ }
2、Java中的泛型不能像C++那么灵活
<T> T add(T a,T b)
{
//return a+b ;//很多人以为java也想C++一样可以这样 ,但是不可以 。
return null;
}
这个返回的null也是有类型限制的,比如上面的ab分别是Integer和String那么就会取他们共同的基类Object做为返回值类型,其他的同理。
3、实现任意类型的数组的成员值的交换,注意在自定义泛型中泛型的实际类型只能是引用数据类型不能是基本数据类型
public static <T> void swap(T[]a,int x,int y)
{
T tem =a[x] ;
a[x]=a[y] ;
a[y]=tem ;
}
上面这个方法如果我 swap(new Integer[]{1,2,3,4,5},1,2); //这样就会自动交换下标12的值。但是这样调用就错了swap(new int[]{1,2,3,5,6},2,3) ; //所以说Java的泛型的实际类型 只能是引用数据类型
4、<T extends String>表示类型只能是String或者String的派生类
<T super String>表示泛型类型只能是String或者String的父类
用法同3
5、下面这个函数利用泛型来实现类型自动转换的功能
public static <T> T autoConvert(Object obj) //因为返回值是 T标识任意类型,所以可以将返回结果赋值给任意类型对象。
{
return (T)obj;
}
Object obj==”";
String str=autoConvert(obj);
可以完成自动转换,因为泛型T代表任意类型,因此他可以赋值给String类型的对象
6、将任意类型的对象填充到任意类型的数组中,与是fillArray(newInteger[]{2,3,4},”ddd”);这样调用是正确的,这样做忽略类型限制
public static <T> void fillArray(T[] a,T b) //将任意一个对象填充到任意类型的数组
{
for(int i =0;i<a.length;i++)
{
a[i] =b ;
}
}
7、以自定义泛型的形式显示一个集合的数据,下面一个是利用自定义泛型一个是利用通配符来实现,但是不同的是利用通配符操作的集合不能向集合中插入元素。但是自定义泛型却可以。原因是通配符代表的集合我们不知道集合内部具体元素是什么类型所以不能对集合进行add操作。
public static <T> void showCollection(Collection<T> col,T obj) //利用泛型来输出任意类型集合
{
col.add(obj) ;
for(T a:col)
{
System.out.println(a);
}
}
public static void showCollection(Collection<?> col) //利用泛型来输出任意类型集合
{
for(Object obj:col)
{
System.out.println(obj);
}
}
8、如果一个类中多个方法都需要泛型那么就是用类级别的泛型。例如
class A<E>
{
public void add(E obj){}
public E get(){}
private E data;
}
这样声明泛型和在函数前面声明其实是一样的只不过是在类的级别上作用于整个类而已
9、要注意泛型只是给编译器看的。也就是说Vector<Integer>Vector<String>他们用到的都是同一份字节码,字节码只有class文件加载到内存中的时候才有。所以在一个类中下面2个方法不能同时存在
void show(Vector<Integer>) {}
void show(Vector<String>){}
通过反射获得泛型的参数化类型:
jdk1.5开始,一个方法可以通过反射获取到他的参数的参数化类型比如:put(Vector<Date> v),通过反射可以获取Date的类型
1.Method里面的方法:
Type[] getGenericParameterTypes()
按照声明顺序返回描述了此 Method 对象所表示的方法的形参类型的 Type 对象的数组。
Type getGenericReturnType()
返回表示由此 Method 对象所表示方法的正式返回类型的 Type 对象。
2.Type是接口,是ParameterizedType的父类
3.ParameterizedType 参数化类型 它放的是泛型的参数化类型实例
Type[] getActualTypeArguments()
返回表示参数的类的的类型参数的Type对象数组。
Type getOwnerType()
返回 Type 对象,返回此类的顶层类的类型。比如O<T>.I<S>,则返回 O<T> 的表示形式
Type getRawType()
返回 Type 对象,表示声明此类型的类或接口。
------- android培训、java培训、期待与您交流! ----------