ArrayList<E> 整个称为泛型类型
ArrayList<E> E称为类型变量或者类型参数
ArrayList<Integer>整个称为参数化的类型
ArrayList<E> Integer称为类型参数的实例或者实际类型参数
ArrayList<E> <>念着type of
ArrayList 称为原始类型
参数化类型和原始类型的兼容性。
Collection<String> c = new Vector();
Collection c = new Vector<String>();
参数化类型不考虑类型参数的继承关系
Vector<String> c = new Vector<Obejct>();
Vector<Obejct> c = new Vector<String>();
都错误。
创建数组时,数组的元素不能使用参数化的类型。
Vector<Integer> vectorList[] = new Vector<String>[10];
错误。
Vector v1 = new Vector<String>();
Vector<Object< v=v1;
错误。
======================
泛型的通配符扩展应用:
错误方式:
public static void printCollection(Collection<Object> collection)
{
for(Object obj:cols)
{
System.out.println(obj);
}
cols.add("string");//没错
//cols = new HashSet<Date>();//会报告错误
}
正确方式:
public static void printCollection(Collection<?> collection)
{
for(Object obj:cols)
{
System.out.println(obj);
}
//cols.add("string");//错误
cols.size();//此方法与类型参数没有关系
cols = new HashSet<Date>();
}
总结:
使用?通配符可以引用其他各种参数化的类型,?通配符
定义的变量主要用作引用,可以调用与参数化无关的方法,
不能调用与参数化有关的方法。
=========================
泛型中的?通配符的扩展
限定通配符的上边界:
true:Vector<? extends Number> x=new Vector<Integer>();
false:Vector<? extends Number> x=new Vector<String>();
? extends Number 表示Number以及子类
Number有8个基本数据类型
String不是Number以及子类,所以不行。
限定通配符的下边界:
true:Vector<? super Integer> x=new Vector<Number>();
false:Vector<? super Integer> x=new Vector<Byte>();
? super Integer 表示Integer或者它的父类。
Byte是平级的,不是父类。
提示:限定通配符总是包括自己。
================
由C++模板函数引入自定义函数
只写一个函数可以适应各种类型
:
template<class T>
T add(T x,T y){
return(T) (x+y);
}
java中的泛型类型类似于C++模板,但仅局限于表面。
java语言的泛型基本上完全是在编译器实现,用于编译器
类型检查和类型推断,然后生成普通的非泛型的字节码。
这种实现技术叫做擦除。(编译器使用泛型类型信息保证
类型安全,然后在生成字节码之前将其清除)
public static <T> int add(T a,T b)
{
return null;
}
//任意类型必须在返回值之前
add(3,6);//装箱成Integer。
Number x1=add(3.5,5);
Object x2=add(3,"adg");
Set集合的Map.Entry方法:
Map<String,Integer> maps = new HashMap<String,Integer>();
maps.add("haha",22);
maps.add("wawa",44);
Set<Map.Entry<String,Integer>> entrys = maps.entrySet()
for(Map.Entry<String,Integer> entry : entrys) {
syso:entry.getKey()+":"+entry.getValue();
}
===========================
写一个程序可以交换数组两个元素的位置
private static void swap(T[] a,int i, int j)
{
T temp=a[i];
a[i]=a[j];
a[j]=temp;
}
swap(new String[]{"abc","yz"},1,2);
//swap(new int[][3],3,5);
//语句会报告编译错误
只有引用类型才能作为泛型方法的实际参数。
为什么不会对new int[3]的int自动装箱和拆箱呢,
因为new int[3]本身就是对象了,你想要的可能就是
int数组,它装箱不就弄巧成拙。
而上面add(3,5);使用基本数据类测试没问题,因为
自动装箱和拆箱。
--------------------------------------------
在定义泛型时也可以用extends限定符。
Class.getAnnotation()方法的定义。并且可以用&来
指定多个边界。如:<V extends Serializable&cloneable>
void method(){}。
普通方法,构造方法,静态方法都可以使用泛型。
也可以用型变量表示异常,称为参数化的异常,可以
用于方法的throws列表中,但是不能用于catch字句中。
private static <T extends Exception>void sayHello() throws T {
try{}
catch(Exception e){
throw (T)e;
在泛型中可以同时有多个类型参数,在定义他们的尖括号中
用逗号分,例如:
public static <K,V> getValue(key){return map.get(key);}
根据调研泛型方法时传递的参数类型和返回值类型来推断,
如果类的实例对象中的多处要用到同一个泛型参数,既这些地方引用的泛型类型要保存
同一个实际类型时,这时候要采用泛型类型的方式进行定义,也就是类级别
的泛型。
public class GenericDao<T> {
private T field1;
public vod save(T obj){}
public T getById(int id){}
}
注意:在对泛型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型。
当一个变量被声明为泛型时,只能被实例变量和方法调用(还有内嵌类型),而不能被静态
方法和静态变量调用。因为静态成员是被所有参数化的类所共享,所以静态成员
不应该有类级别的类型参数。
类中只有一个方法需要使用泛型,是使用类级别的泛型,
还是使用方法级别的泛型?选择类级别的。
------ Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------