一、为什么要有泛型


【1】解决元素存储的安全性问题。

【2】解决获取数据元素时,需要类型强转的问题。


【3】可以统一数据类型,便于操作。

【4】将运行时的异常提前到了编译时,提高了效率。

【5】实现代码的模板化,把数据类型当作参数传递,提高了可重用性。

【6】只要在编译时期没有出现警告,那么运行时期就不会出现 ClassCastException 异常。


public class Demo {

   //泛型在使用时必须左右一致,不存在继承;

   public static void main(String[] args) {

       ArrayList<?> list1 ;

       ArrayList<String> list2 = new ArrayList<String>();

       ArrayList<Integer> list3 = new ArrayList<Integer>();

       ArrayList<Object> list4 = new ArrayList<String>();//泛型在使用时必须左右一致,不存在继承;

       list1 = list2;

       list1 = list3;//不会报错,使用了通配符,通配符表示任意类型,这是在使用,把?当成任何一种类型,

                     //?就是任何类型。

       list2 = list3; //会报错  因为两者在定义时使用泛型,一旦确定了类型就不能够改变类型,

                     //只能是给定的一种泛型类型。

   }

}


   1

   2

   3

   4

   5

   6

   7

   8

   9

   10

   11

   12

   13

   14


二、泛型类


定义在类上的泛型是在创建对象时确定:


public class MyClass1<E> {

   /** 定义具有泛型的类

    * 修饰符 class 类名 <范型变量>{

    * 范型变量一般用E,K,V,T;

    * }

    */

    //......

}


   1

   2

   3

   4

   5

   6

   7

   8


三、泛型接口


由实现类对象确定


/*

   泛型接口(接口上含有泛型)

   格式:

       public abstract interface 接口名<泛型变量> {}

*/

public interface MyInter<T> {

  //......

}


   1

   2

   3

   4

   5

   6

   7

   8


四、泛型方法


创建在放方法上的泛型是在真正调用方法时确定,一般都由传入的参数确定,包含这个方法的类创建对象时,并不会确定方法上的类型,一定在调用方法时确定。


/*

   泛型方法(方法上含有泛型)

   格式:

       修饰符 <泛型变量> 返回值类型 方法名称(参数列表...) {

           //...

       }

*/

public class MyClass02<T> {

   //泛型方法: 泛型E是在方法上自己定义的

   public <E> E getE(E e){

       

   }

}


   1

   2

   3

   4

   5

   6

   7

   8

   9

   10

   11

   12

   13


五、通配符<?>


统配符的使用如下:先说说T和?的区别:基本泛型T是用于定义,将数据类型参数化,不能用于实例化。而 ? 则是在实例化对象时不确定泛型具体参数类型的时候泛指 Object的所有子类型。 但?不能和 Object等效,?是类型实参而不是类型形参,它用于泛指各种类型实参,当具体类型不确定的时候就可以使用?示例如下: