JAVA学习总结之泛型

来源:互联网 发布:淘宝客网站开发 编辑:程序博客网 时间:2024/06/05 19:25
泛型(Gereric):
    允许在定义类,接口,方法时使用类型形参,这个类型形参将在变量声明,创建对象,调用方法时动态的指定(即传入实际的类型实参),
    类型实参在整个接口,类体内可当成类型使用。

注意:  1.包含泛型说明的类型可以在定义变量,创建对象时传入一个类型实参,从而可以动态的生成无数个逻辑上的子类,但是这种子类在物理上并不存在。

        2.当创建带泛型声明的自定义类,为该类定义构造器时,构造器还是原来的类名,不要增加泛型说明。

一、从泛型派生出子类:
    当创建了带泛型的接口,父类之后,可以为该接口创建实现类,或从父类派生子类,但是当使用这些接口或者父类的时候不能再包含类型实参.
    如,下面的代码就是错误的:
    //定义类A继承Apple类,Apple类不能跟类实参
    public class extends Apple<T>{ }

定义和使用方法与定义和使用类,接口的异同:
    1.方法中的形参代表变量,常量,表达式等数据,定义方法时可以声明数据类型,调用方法时必须为这些数据类型传入实际的数据;与此类似的是,定义类,接口,方法时可以声明类型形参,使用类,接口,方法时应该为类型形参传入实际的类型.
          如:
          //使用Apple类时为T形参传入实际的类型参数
      public class A extends Apple<String>{ }
    2.调用方法时必须为所有的数据形参传入参数值,与调用方法不同的是,使用类,接口时也可以不为类型形参传入实际的类型参数,如:
        //使用Apple类时,没有为T形参传入实际的类型参数
        public class A extends Apple{ }

二、并不存在泛型类:
    1.不管泛型的实际类型参数是什么,它们在运行时总有同样的类,在内存中也只占用同一块内存空间,因此在静态方法,静态初始化或者静态变量的声明和初始化中不允许使用类型形参。

    2.由于系统中并不会真正生成泛型类,所以instanceof运算符后不能使用泛型类。

    (补充:
       1. instanceof用于判断前面的对象是否是后面的类,或者其子类、实现类的实例。如果是,则返回true,否则返回false。
       2. instanceof运算符的前一个操作数通常是一个引用类型变量,后一个操作数通常是一个类(也可以是接口,可以把接口理解成一种特殊的类)。

      3.  在进行强制类型转换之前,先用instanceof运行符判断是否可以成功转换,从而避免出现ClassCastException异常,这样可以保证程序更加健壮。

       4. 在使用instanceof运算符需要注意:instanceof运算符前面操作数的编译时类型要么与后面的类相同,要么与后面的类具有父子继承关系,否则会引起编译错误。
    )
注意:
    如果Foo是Bar的一个子类型(子类或子接口),而G是具有泛型说明的类或接口,G<Foo>并不是G<Bar>的子类!这一点非常重要。
    但是数组和泛型有所不同,假设Foo是Bar的一个子类型(子类或子接口),那么Foo[]依然是Bar[]的子类型;但G<Foo>不是G<Bar>的子类型。

三、类型通配符
    1.为了表示各种泛型List的父类,可以使用类型通配符,类型通配符是一个问号(?),讲一个问号作为类型实参传给List集合,写作List<?>(意思是元素类型未知的List),这种写法可以适应于任何支持泛型的接口和类。
        这个问号(?)被称为通配符,它的元素类型可以匹配任何类型,但是这种带通配符的List仅表示它是各种泛型LIst的父类,并不能把元素加入到其中,如下,代码将会引起编译出错:
        List<?> c = new ArrayList<String>();
        //下面引起编译出错(因为无法确定集合中元素的类型)
        c.add(new Object);

    2.类型通配符的上限
        一般的时候,有些方法只能处理一部分数据类型,这时候就可以使用上限和下限来确定这个范围,格式如下:

        泛型上限:
        <? extends 类名>
            public static void function(Student<? extends Number> s){  
                    System.out.println("姓名是:"+s.getName());  
            }  
        表示只能接收Number这个类以及这个类的子类的数据类型。(extends表继承,就是这个类下面的东西)
    
        泛型下限:
        <? super 类>
        表示只能接收Number这个类以及这个类的父类的数据类型。(super表父类,超过这个类的东西)

四、泛型方法:
    在声明方法时定义一个或多个类型形参(类型形参声明以尖括号括起来,多个形参之间以逗号隔开,所有的类型形参声明放在方法修饰符和方法返回值之间)

    1.与接口、类声明中定义的类型不同的是,方法声明中定义的形参只能在该方法里使用,而接口、类中的类型形参则可以在整个接口、类中使用。

    2.与接口、类中使用泛型参数不同的是,方法中的泛型参数无需显示传入实际类型参数。(即即使带参数的方法可以直接使用 方法名())

五、擦除:
    当把一个具有泛型信息的对象赋值给另一个没有泛型信息的变量时,所有尖括号之间的类型信息都将被扔掉.
    如:Java允许直接把List对象赋给一个List<Type>(Type可以是任何类型)类型的变量,但是当把List<Type>对象直接赋给一个List类型的list之后,编译器会丢失前者的泛型信息,
    即丢失List<Type>集合里元素的类型信息,这就是典型的擦除。

六、泛型与数组
    1.Java泛型有一个很重要的设计原则--如果一段代码在编译时没有提出“[unchecked]为经检查的转换”警告,则程序在运行时不会引发ClassCasrException异常。
    因此,数组元素的类型不能包含类型变量或类型形参,除非是无上限的类型通配符。但可以声明元素类型包含类型变量或类型形参的数组。
    也就是说,只能声明List<String>[]类型的数组,但不能创建ArrayList<String>[10]这样的数组对象。

    2.Java允许创建无上限的通配符泛型数组,类如 new ArrayList<?>[10].(程序得进行强制转换)


原创粉丝点击