今天讲讲泛型,也许很多人会说这个都懂,但是还是想回忆下,它也是在写框架中必用的一个知识点,系统的学习一下,我大概对泛型如下几大分类进行讲解!
泛型出现的好处:
泛型是在jdk1.5后出现的,在jdk1.4之前是这么玩的
package com.generic; import java.util.ArrayList; import java.util.List; /** * Created by admin on 2017/2/3. */ public class GenericDemo1 { public static void add(){ List list = new ArrayList(); list.add("a"); list.add("b"); list.add(1);//1自动装箱成对象 } }我们发现List集合中存储了String和Integer二种类型,也许在存储你会发现没啥问题,但是我们存储数据肯定是要拿出来使用的,我们如果对这个集合进行遍历:
Iterator iterator = list.iterator(); while (iterator.hasNext()){ Object obj = iterator.next(); Log.e(TAG,"obj="+obj); }我们发现获取集合中的每个元素返回的是Object,如果这个时候你想对获取的元素进行操作,比如截取等,你会发现最后一个从集合中获取的元素是1,哪它怎么对字符串进行截取等操作啊,哪你是不是要对obj进行类型操作
if(obj instanceof String){ //截取字符串操作 }这样每次都要去判断类型,然后做下面的操作,然后obj是String类型,那么obj就要强转成String,如果obj不是String类型,那么你强转会造成错误的,程序可能直接挂了,这就是为啥出现泛型,因为泛型是出现在编译时期,会避免在运行时候程序因为强转导致程序挂了,多麻烦啊,所以泛型出现的好处有二点
1:避免了强转
2:把运行时期改成了在编译时期检查语法
在jdk源码中到处使用了泛型,特别是在集合中.我们在jdk1.5后使用集合一般就是使用了泛型
你会发现我集合中存储的是String类型,你存储一个进去在编译器就报错了,这就是使用泛型的好处之一
泛型类使用
泛型类意思是泛型定义在类上,
格式:public class A
比如我们在操作数据库的时候在dao层你不知道你操作的是那个对象,所以我们一般都是使用泛型,
package com.generic; /** * Created by admin on 2017/2/3. */ public class BaseDao<T> { public void insert(T entity){ } public void update(T entity, T where){ } }User.java
package com.generic; /** * Created by admin on 2017/2/3. */ public class User { private String id; private String name; private int age; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }使用:
BaseDao这是在操作User对象,你也可以操作Person等其他对象啊,这就是为啥泛型定义在类上,比如我们自定义一个容器,里层还是使用List集合:baseDao = new BaseDao (); User user = new User(); baseDao.insert(user);
package com.generic; import java.util.ArrayList; import java.util.List; /** * Created by admin on 2017/2/3. */ public class CustomList<T> { public List<T> list = new ArrayList<>(); public void add(T t){ list.add(t); } }
框架中泛型用的最多了,平时到的用的很少,但是我们菜鸟也是有梦想的,也是想写框架的,所以必须得学习这些框架的基础知识,
在泛型类型参数化不能使用继承,什么意思呢?
上面我们看到都报错了在程序编译时期,如下写法:
你会发现objs4添加Integer类型就会报错,objs3添加Integer就不会报错,
List这种写法是泛型推断,objs4 = new ArrayList();
List objs3 = new ArrayList这种写法就不是了,所以objs4在编译时期检查语法更加严格!();
泛型接口
泛型接口就是泛型定义在接口上:
package com.example.dao; /** * Created by admin on 2017/1/18. */ public interface IBaseDao<T> { /** * 插入数据 * @param entry * @return */ long insert(T entry); /** * @param entity 更新实体对象 * @param where 更新条件 * @return */ int update(T entity, T where); }这个是操作数据库的dao层,上面定义的是接口,所以要使用必须有具体的类去实现这个接口
package com.generic; import android.util.Log; /** * Created by admin on 2017/2/3. */ public class BaseDao implements IBaseDao使用:{ private static final String TAG ="BaseDao" ; @Override public long insert(User entry) { Log.e(TAG,"name="+entry.getName()); return 0; } @Override public int update(User entity, User where) { return 0; } }
BaseDao baseDao = new BaseDao(); User user = new User(); baseDao.insert(user);上面的BaseDao是实现了IBaseDao接口,并且已经确定了泛型具体的类型就是User,如果这个时候还没确定具体的类型的话,要这么使用:
package com.generic; /** * Created by admin on 2017/2/3. */ public class BaseDao<T> implements IBaseDao<T> { private static final String TAG ="BaseDao" ; @Override public long insert(T entry) { return 0; } @Override public int update(T entity, T where) { return 0; } }UserDao是继承了BaseDao,
package com.generic; import android.util.Log; /** * Created by admin on 2017/2/3. */ public class UserDao extends BaseDao使用:{ private static final String TAG = "UserDao"; @Override public long insert(User entry) { Log.e(TAG,"插入数据"); return super.insert(entry); } @Override public int update(User entity, User where) { return super.update(entity, where); } }
UserDao baseDao = new UserDao(); User user = new User(); baseDao.insert(user);
如果你在那个类上确定了操作那个类(泛型)就可以直接写,不然就写
泛型方法:
泛型方法是泛型定义在方法上,我们做android发现老是去findViewById()显得很麻烦,于是我们可以使用泛型在父类中写个通用的findViewById(),然后在每个子类activity中去使用:
package com.generic; import android.app.Activity; /** * Created by admin on 2017/2/3. */ public class BaseActivity extends Activity { public <T> T $(int resId){ return (T) findViewById(resId); } }子类使用:
button = $(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.e(TAG,"button点击"); } });泛型方法分几种,一种是有返回值,一种是没返回值,还有就是形参中带泛型
没有返回值的泛型方法:
package com.generic; /** * Created by admin on 2017/2/3. */ public class GenericDemo1 { public <T> void print(T t){ System.out.print(t); } }
其中public后面void前面
通过反射绕过编译器检查
List上面是通过反射绕过编译器检查对集合进行操作,集合明明是存储了String类型,但是通过反射我在集合中存储了Integer类型,编译器检查是没问题的,在运行时期会擦除泛型类型,list = new ArrayList<>(); Class extends List> clazz = list.getClass(); try { Method method = clazz.getMethod("add",Object.class); try { method.invoke(list,1); method.invoke(list,2); method.invoke(list,3); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } catch (NoSuchMethodException e) { e.printStackTrace(); }
泛型通配符使用
比如现在有一个需求就是打印出集合中所有的元素,但是你作为leader的话,肯定在想写的代码不能太垃圾要考虑各种情况,比如如果集合中全是String类型或者Integer类型或者自定义对象类型怎么办?我会针对每种都要写一个方法么?哪你肯定这个leader不会做的太久了,于是leader想到了一个解决方法:
package com.generic; import java.util.Collection; /** * Created by admin on 2017/2/3. */ public class GenericDemo1 { public static void printCollection(Collection使用:
使用发现这不行啊,我形参传的是Object类型,但是我实际参数传递的是String类型,这个时候leader就想到了泛型通配符,可以匹配任意类型用 "?"表示
package com.generic; import android.util.Log; import java.util.Collection; /** * Created by admin on 2017/2/3. */ public class GenericDemo1 { private static final String TAG ="GenericDemo1" ; public static void printCollection(Collection> collections){ if(collections!=null&&!collections.isEmpty()){ for(Object obj:collections){ Log.e(TAG,"obj="+obj); } } } }使用:
List这样就没问题了!list = new ArrayList<>(); list.add("1"); list.add("12"); list.add("123"); GenericDemo1.printCollection(list);
但是需求又来了,我一个集合中需要存某一类型,比如我要存储的是Person的子类,
package com.generic; import android.util.Log; /** * Created by admin on 2017/2/3. */ public class Person { private static final String TAG = "Person"; public String name; public int age; public Person(String name, int age) { this.name = name; this.age = age; } public void smoke(){ Log.e(TAG,name+"-"+age+"岁就开始"+"抽中华烟"); } }子类Stu.java
package com.generic; /** * Created by admin on 2017/2/3. */ public class Stu extends Person { public Stu(String name, int age) { super(name, age); } }使用:
Listpersons = new ArrayList<>(); for(int i=0;i<10;i++){ Stu stu = new Stu("zhouguizhi",18+i); persons.add(stu); } add(persons);
public void add(List extends Person> persons){ for(Person p:persons){ p.smoke(); } }? extends Person表示的是集合中存储的是Person以及Person的子类起到限制作用,不是什么对象都能存储
如果集合中存储的是某一类型以及这类型的父类