现在的位置: 首页 > 综合 > 正文

Java 泛型详解

2018年01月31日 ⁄ 综合 ⁄ 共 3629字 ⁄ 字号 评论关闭

首先在没有泛型之前,一旦把一个对象丢进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, 不能操作特有对象。

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

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

抱歉!评论已关闭.