黑马程序员_Java泛型

来源:互联网 发布:informix 端口 编辑:程序博客网 时间:2024/05/29 14:20

---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------

1.什么是泛型

1.1 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
      这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
   1.2 不使用泛型和使用泛型的对比
      1.2.1 在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,
            “任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。
        对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
      1.2.2 泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
   1.3 泛型的规则和限制
      1.3.1 泛型的类型参数只能是类类型(包括自定义类),不能是基本数据类型。
      1.3.2 同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
      1.3.3 泛型的类型参数可以有多个。
      1.3.4 泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上称为“有界类型”。
      1.3.5 泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName("java.lang.String")。
      1.3.6 参数化类型可以引用一个原始类型的对象。
      1.3.7 原始类型也可以引用一个参数化类型的对象。
   1.4 ArrayList<E> 类定义和ArrayList<Integer>类中涉及术语:
      1.4.1 整个ArrayList<E>称为泛型类型。
      1.4.2 ArrayList<E>中的E称为类型变量或类型参数。
      1.4.3 整个ArrayList<Integer>称为参数化的类型。
      1.4.4 ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数
      1.4.5 ArrayList<Integer>中的<>念着typeof
      1.4.6 ArrayList称为原始类型。
   1.5 泛型的使用原理:
      泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,
      编译器编译带类型说明的集合时会去除掉“类型”信息,使程序运行效率不受影响。
      对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。
      由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,
      就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合对象,再调用其add方法即可。
 

2. 限制泛型

   2.1 在上面的例子中,由于没有限制class GenericsFoo<T>类型持有者T的范围,实际上这里的限定类型相当于Object,
       这和“Object泛型”实质是一样的。限制比如我们要限制T为集合接口类型。只需要这么做:
       class GenericsFoo<T extends Collection>,这样类中的泛型T只能是Collection接口的实现类,
       传入非Collection接口编译会出错。
           注意:<T extends Collection>这里的限定使用关键字extends,后面可以是类也可以是接口。
           但这里的extends已经不是继承的含义了,应该理解为T类型是实现Collection接口的类型,或者T是继承了XX类的类型。

3. 通配符泛型

   3.1 为了解决类型被限制死了不能动态根据实例来确定的缺点,引入了“通配符泛型”。
   3.2 针对上面的例子,使用通配泛型格式为<? extends Collection>,“?”代表未知类型,
       这个类型是实现Collection接口。

 3.2.1 如果只指定了<?>,而没有extends,则默认是允许Object及其下的任何Java类了。也就是任意类。
      3.2.2 通配符泛型不单可以向下限制,如<? extends Collection>,还可以向上限制,
            如<? super Double>,表示类型只能接受Double及其上层父类类型,如Number、Object类型的实例。
      3.2.3 泛型类定义可以有多个泛型参数,中间用逗号隔开,还可以定义泛型接口,泛型方法。

4. 泛型方法

   4.1 是否拥有泛型方法,与其所在的类是否泛型没有关系。要定义泛型方法,只需将泛型参数列表置于返回值前。

   4.2 使用泛型方法时,不必指明参数类型,编译器会自己找出具体的类型。泛型方法除了定义不同,调用就像普通方法一样。
   4.3 一个static方法,无法访问泛型类的类型参数,所以,若要static方法需要使用泛型能力,必须使其成为泛型方法。



/*整个称为ArrayList<E>泛型类型ArrayList<E>中的E称为类型变量或类型参数整个ArrayList<Integer>参数化的类型ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数ArrayList<Integer>中<>念typeofArrayList称为原始类型在创建数组实例时,数组的元素不能使用参数化的类型Vertor<Integer> vectorList[] = new Vector<Integer>[10];使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化 有关的方法 */import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;import java.util.ArrayList;import java.util.Collection;import java.util.Vector;public class Test1 {//泛型public static void main(String[] args) throws Exception{// TODO 自动生成的方法存根//Test2();//Test1();//Test3();Test4();}//泛型的好处是把运行时的错误变成编译时的错误,取出时候还不需转换private static void Test2() {ArrayList collection1 = new ArrayList();collection1.add(1);collection1.add(1L);collection1.add("abc");int i = (Integer)collection1.get(1);}private static void Test1() {ArrayList<String> collection1 = new ArrayList<String>();//collection1.add(1);//collection1.add(1L);collection1.add("abc");String element = collection1.get(0);//int i = (Integer)collection1.get(1);System.out.println(element);//<Integer>的可以传入,<String>类型的也可以传printCollection(collection1);}//泛型在反射技术中的应用private static void Test3() throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{//Constructor<String> constructor = String.class.getConstructor(StringBuffer.class);Constructor<String> constructor = String.class.getConstructor(StringBuffer.class);String str2 = constructor.newInstance(new StringBuffer("abc"));System.out.println(str2.charAt(2));//Vector<Integer> vectorList[] = new Vector[10];}//把字符串放入ArrayList<Integer>集合中去private static void Test4() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{ArrayList<Integer> list = new ArrayList<Integer>();list.add(1);//list.add("abc");//由于泛型只作用于编译阶段,所以可以用反射区获取add方法list.getClass().getMethod("add", Object.class).invoke(list, "abc");System.out.println(list.get(1));//<Integer>的可以传入printCollection(list);}//打印出任意类型的集合元素private static void printCollection(Collection<?> collection){System.out.println("集合中的元素个数:"+collection.size());for(Object obj:collection){System.out.println(obj);}}}


自定义泛型:
package cn.hmm.Generic;import java.util.Collection;import java.util.HashMap;import java.util.Map;import java.util.Set;public class Test2 {public static void main(String[] args) {// TODO 自动生成的方法存根//MapDemo();Integer[] a = new Integer[]{1,2,3,4};//char[] b = new char[]{'a','b','c','d'};//基本数据类型不能转换swap(a,1,2);for(Integer c:a){System.out.println(c);}Object obj = "abc";String str = AutoConvert(obj);}//泛型一些应用private static void MapDemo() {HashMap<String,Integer> maps = new HashMap<String,Integer>();maps.put("ccz", 26);maps.put("hmm", 24);maps.put("hhc", 24);Set<Map.Entry<String, Integer>> entrySet = maps.entrySet();for(Map.Entry<String, Integer> entry : entrySet){System.out.println(entry.getKey() + ":"+entry.getValue());}}private static <T> void copy1(Collection<T> c,T[] a){}private static <T> void copy2(T[]  c,T[] a){}//打印出任意类型的集合元素private static <T> void printCollection(Collection<T> collection,T obj2){System.out.println("集合中的元素个数:"+collection.size());for(Object obj:collection){System.out.println(obj);}collection.add(obj2);}private static <T> void fillArray(T a[],T obj){for(int i =0;i<a.length;i++){a[i] = obj;}}//private static <T> T AutoConvert(Object obj){return (T)obj;}//交换任意类型的数组的两个元素,泛型的类型不能是基本类型private static <T> void swap(T[] a,int i,int j){T temp = a[i];a[i] = a[j];a[j] = temp;}}




泛型<E>定义在类上面,表示类里面的所有的非静态方法上的E都是一样的,如果静态的也要用泛型,需要自己去定义.

:

package cn.hmm.Generic;import java.util.Set;//dao Data access Object  -->crud(Create,Read,update,delete)public class GenericDao<E> {public void add(E x){}public E findById(int id){return null;}public void delete(E obj){}public void delete(int id){}public void update(E obj){}public E findByname(String name){return null;}//如果是静态方法,要自己在方法上定义public static <T> void update2(T obj){}public Set<E> findByConditions(String s){return null;}}



利用反射拿到集合中泛型的实际类型:
package cn.hmm.Generic;import java.lang.reflect.Method;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.util.Date;import java.util.Vector;public class GenericTest {public static void main(String[] args) throws NoSuchMethodException, SecurityException {// TODO 自动生成的方法存根//根据下面这个是没办法得到集合的类型的,但是可以根据方法,把集合当成参数传入//Vector<Date> v = new Vector<Date>();Method applyMethod = GenericTest.class.getMethod("applyVector", Vector.class);Type[] types = applyMethod.getGenericParameterTypes();ParameterizedType pType = (ParameterizedType)types[0];System.out.println(pType.getRawType());System.out.println(pType.getActualTypeArguments()[0]);}public static void applyVector(Vector<Date> v1){}}


总结:
1:将运行时期的问题ClassCastException问题转换成了编译失败,体现在编译时期,程序员就可以解决问题。
2:避免了强制转换的麻烦。

---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------

详细请查看:www.itheima.com

0 0
原创粉丝点击