泛型总结

------- android培训java培训、期待与您交流! ----------

因为集合中可以存储任意类型的对象,在灵活的同事,也为程序带来了安全隐患。

(所以出现了)(个人猜测)泛型的概念。

比较:

List ls1 = new ArrayList();
List<String> ls2 =  new ArrayList<String>();

可以往ls里存任何类型的数据,但ls2中只能(有条件,比如通过反射的方式可以存储其他类型对象进去)存放String类型的数据。
这样在后续对集合中对象的使用时,避免了强转,提高了代码的简洁性和安全性。

有时候,我们在定义一个方法的时候,需要处理多种类型的对象,如果为多种类型的对象写多个重载方法则显得累赘。
比较下面三个方法:

void printCollection(Collection c) {// 不使用泛型
    Iterator i = c.iterator();
    for (k = 0; k < c.size(); k++) {// 不知道集合里存的什么类型对象,不能用增强for循环,因为增强for循环需要指定对象的类型
        System.out.println(i.next());
    }
}
void printCollection(Collection<Object> c) {// 使用泛型
    for (Object e : c) {// 可用增强for循环
        // 如果传入的集合c是ArrayList<String>则会出错
        System.out.println(e);
    }
}
void printCollection(Collection<?> c) {// 使用泛型<?>表示任意类型,该方法可打印任意类型的集合
    for (Object e : c) {
        System.out.println(e);
    }
}

但是使用<?>会有一个比较大的问题,向集合中添加元素应该是任意类型的,但是只有null是任意类型的。所以有了<? extends T>(表示任意T类型和其子类)和<? Super T>(表示任意T类型和其父类)。

假设有3个类,Person、Student、Worker,其中Student和Work是Person的子类。

ArrayList<Person> a1= new ArrayList<Person>();
ArrayList<? extends Person> a2= new ArrayList<Person>();
ArrayList<? super Student> a3= new ArrayList<Person>();

ArrayList<Person>  b1= new ArrayList<Student>();
ArrayList<Student> b2= new ArrayList<Student>();
ArrayList<Worker> b3= new ArrayList<Worker>();

a1 =b1; /*通过编译*/ a1 =b2;/*编译失败*/ a1 =b3;/*编译失败*/ 
a2 =b1; /*通过编译*/ a2 =b2;/*通过编译*/ a2 =b3;/*通过编译*/ 
a3 =b1; /*通过编译*/ a3 =b2;/*通过编译*/ a3 =b3;/*编译失败*/ 

一般来说,<? extends T>比较常用,而<? Super T>极少用的。因为在后续的使用中<? extends T>可以使用父类中的方法。而<? Super T>则不能调用T类型的方法。

一个别人的总结:我觉得很好!
如果你想从一个数据类型里获取数据,使用<? extends T>通配符
如果你想把对象写入一个数据结构里,使用<? Super T>通配符
如果你既想存,又想取,那就别用通配符。

 

泛型方法:

一个把数组中的对象存到集合中的方法。

static void fromArrayToCollection(Object[] a, Collection<?> c) {
    for (Object o : a) {
        c.add(o); // 编译错误,因为只有null是任意类型的。
    }
}

使用泛型方法,注意static <T> void。

static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
    for (T o : a) {
        c.add(o);// 可以编译通过,也可运行。
    }
}

需要注意的是,在我们使用泛型方法的时候一般不需要加上传递类型参数,系统会自动判断并调用合适的方法(取两种类型的共同父类)(见例1)。但是如果有了同名的普通方法时,就有可能需要指定了。(见例2)

例1:

Object[] oa = new Object[100]; 
Collection<Object>co = new ArrayList<Object>(); 
  fromArrayToCollection(oa, co);// T被认为是Object 
String[] sa = new String[100]; 
Collection<String>cs = new ArrayList<String>(); 
  fromArrayToCollection(sa, cs);// T被认为是String 
  fromArrayToCollection(sa, co);// T被认为是Object 
Integer[] ia = new Integer[100]; 
Float[] fa = new Float[100]; 
Number[] na = new Number[100]; 
Collection<Number>cn = new ArrayList<Number>(); 
  fromArrayToCollection(ia, cn);// T被认为是Number 
  fromArrayToCollection(fa, cn);// T被认为是Number 
  fromArrayToCollection(na, cn);// T被认为是Number 
  fromArrayToCollection(na, co);// T被认为是Object 
  fromArrayToCollection(na, cs);// 编译错误

例2:

public  <T> void go(T t) { 
    System.out.println("泛型方法"); 
} 
public void go(String str) { 
    System.out.println("普通方法"); 
} 
public static void main(String[] args) { 
        FuncGenric fg = new FuncGenric(); 
        fg.go("haha");  //打印“普通方法”
        fg.<String>go("haha"); //打印“泛型方法”
        fg.go(new Object()); //打印“泛型方法”
        fg.<Object>go(new Object());//打印“泛型方法”
}

感觉个人对泛型的理解还不够深入,需要在看文档和学习的时候多多思考。

posted @ 2013-01-03 16:42  qinbin  阅读(260)  评论(0编辑  收藏  举报