泛型总结
------- 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());//打印“泛型方法” }
感觉个人对泛型的理解还不够深入,需要在看文档和学习的时候多多思考。