Java 泛型详解

来源:互联网 发布:档案管理系统软件源码 编辑:程序博客网 时间:2024/05/17 03:06

首先在没有泛型之前,一旦把一个对象丢进java集合中,集合就会忘记对象的类型,把所有对象当成Object类型来处理。当程序从集合中取出对象时,就需要进行强制类型转换,这种强制类型转换不仅代码臃肿,而且容易引起ClassCastException异常。

    public class ListErr    {        public static void main(String[] args)         {            //创建一个只想保存字符串的List集合            List strList = new ArrayList();            strList.add("Struts2权威指南");            strList.add("基于J2EE的Ajax宝典");            strList.add("轻量级J2EE企业应用实战");            //”不小心“把一个Integer对象”丢进"了集合            strList.add(5);            for (int i = 0; i < strList.size() ; i++ )            {                //因为List里取出的全部是Object,所以必须强制类型转换                //最后一个元素将出现ClassCastException异常                String str = (String)strList.get(i);            }        }    }

为了解决这个问题,在1.5前都采用,创建个List对象的方法,但每遇到个集合都要建个对象,eg    class StrList    {        private List strList = new ArrayList();        //定义StrList的add方法        public boolean add(String ele)        {            return strList.add(ele);        }        //重写get方法,将get方法的返回值类型改为String类型        public String get(int index)        {            return (String)strList.get(index);        }        public int size()        {            return strList.size();        }    }

public class CheckType{    public static void main(String[] args)     {        //创建一个只想保存字符串的List集合        StrList strList = new StrList();        strList.add("Struts2权威指南");        strList.add("基于J2EE的Ajax宝典");        strList.add("轻量级J2EE企业应用实战");        //下面语句不能把Integer对象“丢进”集合中,将引起编译异常        strList.add(5);        System.out.println(strList);        for (int i = 0; i < strList.size() ; i++ )        {            //因为StrList里元素的类型就是String类型,所以无需强制类型转换            String str = strList.get(i);        }    }}
有了泛型就方便了,eg    public class GenericList    {        public static void main(String[] args)         {            //创建一个只想保存字符串的List集合            List<String> strList = new ArrayList<String>();            strList.add("Struts2权威指南");            strList.add("基于J2EE的Ajax宝典");            strList.add("轻量级J2EE企业应用实战");            //下面代码将引起编译错误            strList.add(5);            for (int i = 0; i < strList.size() ; i++ )            {                //下面代码无需强制类型转换                String str = strList.get(i);            }        }    }

当创建带泛型的自定义类时,在定义该类构造器时,构造器名还是和类名一样,不要增加泛型声明。

从泛型类派生子类,接口,父类不能包含类型形参。

下面例子就是错误的。

public class A extends B<T>{},

使用类型通配符“?’”, 它可以匹配任何类型,

public void test(List <?>){}


使用时注意:List<String>不是List<Object>子类特殊的泛型(带类型通配符和类型上限),eg    public class Apple<T extends Number>    {        T col;                public static void main(String[] args)        {            Apple<Integer> ai = new Apple<Integer>();            Apple<Double> ad = new Apple<Double>();            //下面代码将引起编译异常            //因为String类型传给T形参,但String不是Number的子类型。            Apple<String> as = new Apple<String>();                    }    }java泛型不支持泛型数组(List<String> aa=new ArrayList<String>[10];),因为java泛型的设计原则是没有unchecked警告就没有ClassCastExcepiton. 我建议大家遇到集合数组等的时候,自己来检验数据的类型,eg    public class test {        public static void main(String[] args) {            ArrayList[] aa = new ArrayList[10];            List<Integer> li = new ArrayList<Integer>();            li.add(3);            ((Object[]) aa)[1] = li;            Object target = aa[1].get(0);            if (target instanceof Integer) {                Integer s = (Integer) target;                System.out.println(s);            }        }    }由于java的泛型只是编译时做下检验,大家不要想的过于强大,他的最大作用只是增强代码的可读性,别的方面也没见多大的作用。

什么时候写泛型?有什么好处?

最简单的体现,只要使用到了带有<>的类和接口,就指定具体对象类型。

 

泛型的好处:

1,  将运行时出现的ClassCastException问题,再编译时期给解决了。运行就安全了。

2,  避免了强制转换的麻烦。

 

所以泛型就是JDK1.5后出现的一个安全机制。


泛型的理解?

首先在没有泛型之前,一旦把一个对象丢进java集合中,集合就会忘记对象的类型,把所有对象当成Object类型来处理。

         当程序从集合中取出对象时,就需要进行强制类型转换,这种强制类型转换不仅代码臃肿,而且容易引起ClassCastException异常。

         1,泛型就是传参数。

2,泛型替代了Object。


什么是泛型的擦除和补偿?

泛型是编译时期的安全机制。

         编译时,通过泛型机制,编译器多了多元素类型进行检查的步骤。

         如果检查通过,产生的class文件时不带有泛型的:也就是泛型的擦除。

 

         泛型的补偿:在对元素存储的时候,可以完成类型的判断。

                                     可是在对元素取出的时候,怎么用指定的类型来接收呢?

                                     JVM运行时,会获取元素的类型,并用该类型对元素进行转换即可。


什么时候使用泛型类?

当类中要操作的引用数据类型不确定的时候,以前使用的是共性类型Object,

现在可以使用泛型来解决。


什么时候使用泛型方法?

当方法操作的引用数据类型不确定的时候,就使用泛型方法。

 

如果方法是静态的,是无法访问类上定义的泛型的。

如果该方法还需要泛型。

必须将泛型定义在方法上。


泛型的限定。

如果要对操作的类型进行限定,只操作一部分类型时,可以使用泛型的高级功能。

?extends E:可以接收E类型和E的子类型。这叫泛型的上限。

?super E:可以接收E类型或E的父类型。这叫泛型的下限。


什么时候会用? extends E 呢?(往集合中添加集合的时候经常使用)

一般在存储具体引用类型时,使用这种情况。

因为存储E类型或者E类型的子类型,在取出的时候都可以用E类型来操作这些元素。

这时可以保证类型是安全的。


下限什么时候用?

从集合中取出对象进行操作时,可以使用下限。

例如:比较器。无论集合中的元素对象的类型是什么,只要比较器的指定的类型可以接收这些对象完成比较,就可以了。

所以比较器的类型,可以是集合中当前元素的类型,也可以是该元素类型的父类型。


泛型使用的误区:

1,  凡是安全的都特别严格。一定要保证座左右两边一致。

2, 不能操作特有对象。

参数定义的集合类型是一个范围,而接受的实际参数是以一个实体,该实体肯定会指定该范围中的某一个具体类型。而该类型是创建容器时指定的,到底是哪种类型该方法是不确定的,那么就不可以在该方法内,进行具体类型对象的定义和操作。

 建议定义泛型时,左右两边一定要一致。如果不一致要保证一点,左边在声明时可以声明一个类型范围,右边在实例化时指定的具体类型必须是左边类型范围中的一种。




原创粉丝点击