泛型

泛型

泛型:在定义类,接口,方法时使用类型形参,这个类型形参将在声明变量、创建对象、调用方法时动态地指定(即传入实际的类型参数,也可以称为类型实参)。

在定义的接口,类中声明形参,类型形参在整个接口,类里可当成类型使用。

List<String> l1 = new ArrayList<>();

List<String> l2 = new ArrayList<>();

l1.getClass() == l2.getClass(); //返回true  不存在泛型类 不管泛型的实际类型参数是什么,他们在运行的时候总是同样一个类

不管为泛型的类型形参传入哪一种类型实参,对于java来说,他们依然被当成同一个类处理,在内存中也只占一块内存空间,因此在静态方法、静态初始化块或者

静态变量的声明和初始化中不允许使用类型形参。

public class Car<T>

{

      //下面代码错误 不能在静态变量声明中使用类型形参

       static T info;

       T age;

       //下面代码错误 不能再静态方法声明中使用类型形参

       public static void getCarBrand(T msg){}

}

类型通配符

为了表示各种泛型List的父类,可以使用类型通配符,类型通配符是一个问号(?),将一个问号作为类型实参传给List集合,写作:List<?>。这个问号被称为通配符,表示它的元素类型可以匹配任何类型。

设定类型通配符的上限

 1 public class Apple<T extends Number> {
 2     T price;
 3     
 4     public static void main(String[] args){
 5         Apple<Integer> ai = new Apple<>();
 6         Apple<Double> ad = new Apple<>();
 7         
 8         //此处编译异常 此处将String传给T形参,但是String不是Number的子类型,会引起编译错误
 9         Apple<String> as = new Apple<>();
10     }
11 }

使用类型通配符设定类上限,传入的参数类型必须为上限类型或者上限类型的子类。

Integer和Double类型都必须为Number类型的子类。

泛型方法

语法格式:

 修饰符 <T, S> 返回类型 方法名(方法参数){
        //方法体
    }
 1 public class TestError {
 2     //定义一个将任意类型数组值复制到集合中的方法
 3     public static <T> void formArrayToCollection(T[] arry, Collection<T> c) {
 4         for (T t : arry) {
 5             c.add(t);
 6         }
 7     }
 8      
 9     public static void main(String[] args) {
10         String[] arr = {"Bob", "Jack", "Marry"};
11         List<String> list = Lists.newArrayList();
12         formArrayToCollection(arr, list);
13         list.forEach(System.out::println);
14     }
15 }

 设定类型通配符的下限

 1 public class TestError {
 2 
 3     public static <T> void formArrayToCollection(T[] arry, Collection<T> c) {
 4         for (T t : arry) {
 5             c.add(t);
 6         }
 7     }
 8      //将一个集合中的元素复制到另外一个集合里面,并返回集合最后一个元素的值
 9     public static <T> T copyType(Collection<T> des, Collection<? extends T> src){
10          T last = null;
11          /*src的类型必须为类型T或者类型T的子类,返回最后一个值得类型为T类型。
12          * src集合里面的元素类型可能是T类型或者T类型的子类,
13          */
14          for (T t : src){
15              des.add(t);
16              last = t;
17          }
18          return last;
19     }
20 
21     public static void main(String[] args) {
22       List<Integer> src = Lists.newArrayList();
23       for (int i = 0; i< 10; i++){
24           src.add(i);
25       }
26       List<Number> des = Lists.newArrayList();
27       //此处得到的是Number类型,然而这个方法明显返回的类型应该是Integer类型,丢失了集合元素值得类型
28       Number last = copyType(des, src);
29       //Integer last = copyType(des, src);此处会报错
30       System.out.println(last);
31       des.forEach(System.out::println);
32     }
33 }

采用上面这个方法丢失了集合元素的类型。

改进:设定通配符的下限。Java中使用<? super Type>来设定通配符的下限,这个通配符表示元素类型必须为Type本身或者Type的父类。于是采用通配符的下限来改写上述的Copy方法;

 1 public class TestError {
 2 
 3     public static <T> void formArrayToCollection(T[] arry, Collection<T> c) {
 4         for (T t : arry) {
 5             c.add(t);
 6         }
 7     }
 8 
 9     public static <T> T copyType(Collection<? super T> des, Collection<T> src){
10          T last = null;
11          /*src的类型必须为类型T或者类型T的子类,返回最后一个值得类型为T类型。
12          * src集合里面的元素类型可能是T类型或者T类型的子类,
13          */
14          for (T t : src){
15              des.add(t);
16              last = t;
17          }
18          return last;
19     }
20 
21     public static void main(String[] args) {
22       List<Integer> src = Lists.newArrayList();
23       for (int i = 0; i< 10; i++){
24           src.add(i);
25       }
26       List<Number> des = Lists.newArrayList();
27       //此处得到的是Number类型,然而这个方法明显返回的类型应该是Integer类型
28       //Number last = copyType(des, src);
29       // 此处可以使用Integer类型
30       Integer last = copyType(des, src);
31       System.out.println(last);
32       des.forEach(System.out::println);
33     }
34 }

使用上述这个方法可以使得copyType()方法推断出最后一个被赋值的元素类型是Integer类型,而不是笼统的Number类型。

posted @ 2020-04-02 14:19  seedss  阅读(142)  评论(0编辑  收藏  举报