泛型
来源:互联网 发布:mac zip 打不开 编辑:程序博客网 时间:2024/06/07 14:12
一:概述
/**
* 在jdk1.5之前,我们在往一个集合中存放一个对象或者基本数据类型的时候,取出来的时候,如果数据类型
* 不匹配,那么就不可避免的需要做一些强制类型转换的工作,那么这就不可避免的出现类型转换异常。
*/
二:Demo1
<span style="font-size:18px;"><span style="font-size:18px;">package cn.itcast.generic;import java.util.ArrayList;import java.util.List;/** * 为何我们需要使用泛型? * User: OF895 * Date: 14-7-21 * Time: 下午9:51 */public class Demo1 { /** * 在jdk1.5之前,我们在往一个集合中存放一个对象或者基本数据类型的时候,取出来的时候,如果数据类型 * 不匹配,那么就不可避免的需要做一些强制类型转换的工作,那么这就不可避免的出现类型转换异常。 */ public static void main(String[] args) { List list = new ArrayList(); list.add("aaaa"); //这里我们在取出list集合中的值的时候,如果我们使用了Integer去转换 //这个程序在编码的时候不会报错,但是在运行的时候,就会发生异常,ClassCastException. //这对于一个大型的程序是有风险的,为了解决这个问题,我们尽量让其在编码期间,程序员就能够去发现这个为问题。 //所以jdk1.5之后出现了泛型 ,详见demo2 Integer integer = (Integer) list.get(0); }}</span></span>
三:Demo2
<span style="font-size:18px;"><span style="font-size:18px;">package cn.itcast.generic;import java.util.ArrayList;import java.util.List;/** * 使用泛型的方式,去解决demo1中可能出现的问题 * User: OF895 * Date: 14-7-21 * Time: 下午9:59 */public class Demo2 { public static void main(String[] args) { //这里我们限制了使用泛型,所以这个list中只能够存放String类型的参数 //否则在编码期间就会报错 List<String> list = new ArrayList<String>(); list.add("hello world"); }}</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">package cn.itcast.generic;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Map.Entry;import java.util.Set;/** * map集合中使用泛型 * User: OF895 * Date: 14-7-21 * Time: 下午10:07 */public class Demo3 { public static void main(String[] args) { Map<Integer, String> map = new HashMap<Integer, String>(); map.put(1, "aa"); map.put(2, "bb"); map.put(3, "cc"); map.put(4, "dd"); map.put(5, "ee"); /** * * 取出map集合中存放的值 */ Set<Map.Entry<Integer, String>> set = map.entrySet(); Iterator<Entry<Integer, String>> iterator = set.iterator(); while (iterator.hasNext()) { Entry<Integer, String> entry = iterator.next(); //通过迭代得出的key Integer key = entry.getKey(); //通过迭代得出的value String value = entry.getValue(); System.out.println(key + " : " + value); } }}</span></span>
五:Demo4
<span style="font-size:18px;"><span style="font-size:18px;">package cn.itcast.generic;import java.util.ArrayList;import java.util.Collection;import java.util.LinkedList;/** * User: OF895 * Date: 14-7-23 * Time: 下午11:11 */public class Demo4 { public static void main(String[] args) { save(new ArrayList<String>()); save(new LinkedList<Integer>()); } //当我们在设计一个方法的时候,如果不确定方法的调用者,会传入声明类型的参数 //那么我们可以使用“?”这个通配符 //注意点:使用通配符的时候的注意点: //不能再使用“参数”与“具体类型”相关的方法。 public static void save(Collection<?> c){ //切记:这里就不能这么写了,为什么? //其实很好理解,因为我们不确定这个方法的调用者,会传入什么类型的参数 //如果这里直接添加的是String类型的,而上面调用save()方法时候,传入的是Integer类型,怎么办? // c.add("hello world"); }}</span></span>
六:泛型声明在“类”上面。(需要先声明,再使用)
<span style="font-size:18px;"><span style="font-size:18px;">package cn.itcast.generic;/** * 自定义泛型类 * <p/> * <p/> * 为什么要将泛型声明在类上面? * 1 当我们一个类中,多个方法使用到同一种类型的泛型的时候(比如T泛型),避免在每一个方法上面都声明T,那么我们 * 可以考虑将泛型声明放在类上面,这样在方法上就可以不声明了(注意必须是这个类中的方法) * <p/> * 2当泛型被声明在类上面的时候,它的作用域仅限于这个类里面。 * <p/> * 3声明在类上面的方法,只可以在类中的“非静态”方法上面使用,静态方法如果需要使用泛型,那么仍然需要自己去声明,然后再使用。 * <p/> * User: OF895 * Date: 14-7-22 * Time: 上午12:10 */public class GenericClass<T> { public void methodA(T t) { System.out.println("这里的泛型T,因为定义在了类上面,所以这个类里面的方法都是可以使用这个泛型的"); } public <E> void methodB(E e) { System.out.println("这里的泛型E,因为没有在类上面声明,所以在使用之前需要在方法上先声明"); } public static <T> T methodC(T t) { System.out.println("在泛型类上面声明的泛型变量,是不可以直接使用在“静态方法”上面的,需要我们自己在方法上面去声明"); return null; }}</span></span>
七:泛型声明在“方法”上
<span style="font-size:18px;"><span style="font-size:18px;">package cn.itcast.generic;/** * 泛型方法的使用(自定义泛型方法) * User: OF895 * Date: 14-7-21 * Time: 下午11:26 */public class GenericMethod { /** * 自定义泛型方法 * <T> 这个代表声明T,在java中,任何变量使用之前,都需要先声明,然后才可以使用,这是一种语法。 * <p/> * T:代表的是方法methodA的返回值类型是T,也就意味着我们在参数T中传入声明类型,那么返回值就是什么类型。 */ public <T> T methodA(T t) { T obj; obj = t; return obj; } public <T, E, F> void methodB(T t, E e, F f) { System.out.println("在自定义泛型方法中,我们是可以定义多个泛型参数的,只需要在使用之前都声明一下就可以了"); }}</span></span>
八:自定义“泛型”方法的一个例子(自定义一个reverse的方法,接受任意类型的数组,数组的元素顺序颠倒)
<span style="font-size:18px;"><span style="font-size:18px;">package cn.itcast.generic;import java.util.Arrays;import java.util.Collections;import java.util.List;/** * 自定义一个reverse的方法,接受任意类型的数组,数组的元素顺序颠倒。 * User: OF895 * Date: 14-7-21 * Time: 下午11:56 */class ReverseArray { public <T> void reverse(T[] t){ List list = Arrays.asList(t); Collections.reverse(list); for(Object i: list){ System.out.println(i); } }}</span></span>
测试上面的代码:
<span style="font-size:18px;"><span style="font-size:18px;">public class Test { public static void main(String[] args) { String[] arr = new String[]{"a","b","c","d","e"}; Integer[] arrInt = new Integer[]{1,2,3,4,5,6}; ReverseArray reverseArray = new ReverseArray(); reverseArray.reverse(arrInt); }}</span></span>
九:“增删改查”的一个“基类”(使用泛型的好例子)
JavaBean:
<span style="font-size:18px;"><span style="font-size:18px;">package cn.itcast.advance;/** * User: OF895 * Date: 14-7-23 * Time: 下午10:01 *///“种类”的javabeanpublic class Category {}</span></span>
BaseDao:
<span style="font-size:18px;"><span style="font-size:18px;">package cn.itcast.advance;import org.hibernate.Session;/** * * 一个增删改查的基类 * User: OF895 * Date: 14-7-23 * Time: 下午9:24 */public class BaseDao<T> { private Session session; private Class clazz; //如果某个子类实现了BaseDao,那么就调用一下这个构造方法 //掺入具体子类的class对象 public BaseDao(Class clazz) { this.clazz = clazz; } //增加 public void add(T t){ session.save(t); } //查找 public T find(String id){ //1在hibernate中,要查找某个对象,是根据传入的id,来作为条件的 //但是这里有个问题,在查找获得这个对象的时候,我们需要传入“被查找”对象的class,但这个是无法通过泛型T,t.getClass或者t.class获得,泛型不能这么使用 //那么如何解决这个问题? //方法:使用构造方法,由使用这个类的子类去传入。 return (T) session.get(clazz,id); } //更新 public void update(T t){ session.update(t); } //删除 public void delete(String id){ //在hibernate框架中,要实现删除,需要两步走 //1首先根据传入的id,“查找”出这个对象 //2然后再“删除”这个对象。 T t = (T) session.get(clazz,id); session.delete(t); }}</span></span>
CategoryDao:(这里在)
<span style="font-size:18px;"><span style="font-size:18px;">package cn.itcast.advance;/** * User: OF895 * Date: 14-7-23 * Time: 下午10:01 *//** * * 这里这个CategoryDao只要继承了BaseDao,那么它就拥有了“增删改查”的方法,这也是面向对象的设计方法 */public class CategoryDao extends BaseDao<Category> { //因为我们在使用BaseDao中的“增删改查”的方法的时候,需要传入具体子类的class类型,指明是那个具体的子类。 //所以这里我们通过子类调用父类的构造函数的方式去传入。 //思考:这样虽然可以实现不同对象都调用BaseDao的方法,但是代码不够优雅。需要显示调用父类的构造方法,传入字节码文件,有更优雅的实现方式。 public CategoryDao() { super(CategoryDao.class); }}</span></span>
十:
javabean:
<span style="font-size:18px;"><span style="font-size:18px;">package cn.itcast.newAdvance;/** * User: OF895 * Date: 14-7-23 * Time: 下午10:33 */public class Book {}</span></span>
NewBaseDao:(这里优化了例子9中的代码,提高了代码的优雅性,我们不需要在子类中的构造方法中传入类型了)
<span style="font-size:18px;"><span style="font-size:18px;">package cn.itcast.newAdvance;import org.hibernate.Session;import java.lang.reflect.ParameterizedType;/** * 一个基类:实现增删改查 * User: OF895 * Date: 14-7-23 * Time: 下午10:20 */public class NewBaseDao<T> { //org.hibernate.Session,通过这个类可以使用“增删改查” private Session session; private Class clazz; public NewBaseDao() { Class cla = this.getClass();//这里首先要明白一点:当子类实现这个父类的时候,在子类new对象的时候,会隐式的调用父类的“无参”构造方法,那么这里this指的就是子类,所以这里的class也是“子类”的class. ParameterizedType parameterizedType = (ParameterizedType) cla.getGenericSuperclass();//这个方法获得的就是父类的“泛型类型”,类似于BaseDao<Category>,或者BaseDao<Book>,这个后面的参数就是由具体的子类去决定的。 /** * 不能写成: clazz = parameterizedType.getActualTypeArguments()[0].getClass; * * 这里为什么要写成parameterizedType.getActualTypeArguments()[0]? * * 因为 NewBaseDao<Category,Book>,这个后面的实际的泛型对象,可能有多个,我们需要显示指明具体的哪一个泛型。 */ //通过这样的构造方法,那么我们子类在实现这个NewBaseDao的时候,就不需要通过构造函数参入class了,因为父类,会自己通过反射去查找,这样代码更加优雅。 clazz = (Class) parameterizedType.getActualTypeArguments()[0]; System.out.println(clazz); } //增加 public void add(T t) { session.save(t); } //查找 public T find(String id) { //1在hibernate中,要查找某个对象,是根据传入的id,来作为条件的 //但是这里有个问题,在查找获得这个对象的时候,我们需要传入“被查找”对象的class,但这个是无法通过泛型T,t.getClass或者t.class获得,泛型不能这么使用 //那么如何解决这个问题? //方法1:使用构造方法,由使用这个类的子类去传入。 //方法2:当某个“子类”去实现这个“基类”的时候,由基类自己去获得子类的class类型 return (T) session.get(clazz, id); } //更新 public void update(T t) { session.update(t); } //删除 public void delete(String id) { //在hibernate框架中,要实现删除,需要两步走 //1首先根据传入的id,“查找”出这个对象 //2然后再“删除”这个对象。 T t = (T) session.get(clazz, id); session.delete(t); }}</span></span>
BookDao:
<span style="font-size:18px;"><span style="font-size:18px;">package cn.itcast.newAdvance;/** * User: OF895 * Date: 14-7-23 * Time: 下午10:34 */public class BookDao extends NewBaseDao<Book> { public static void main(String[] args) { //在BaseDao中,做了操作后,这里在new子类对象的时候,就会默认调用“父类”构造方法了 BookDao bookDao = new BookDao(); }}</span></span>
0 0