java泛型程序设计基础知识总览

来源:互联网 发布:影武者 冰川网络 编辑:程序博客网 时间:2024/06/08 18:35

泛型介绍

泛型程序设计(Generic programming):可以被很多不同的类型的对象所重用。比那些直接使用Object变量,然后强制类型的转换的代码具有更好的安全性和可读性。

使用类型参数(type parameters)可以将需要使用的类型,提前声明。如:

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

使用类型参数可以告知这个类适用于什么类型,当调用对应的get()方法的时候,不需要进行强制类型转换,编译器本身就知道其对应的类型。

当实现一个泛型的时候非常不容易,因为你需要知道这个这个类对应的所有用途及其类型,所以Java提供了通配符类型,来解决这个问题。

定义简单泛型类

泛型类,就是指具有一个或者多个类型变量,也就是说这个类适应这几种类型。

使用类型变量T,用<>括起来,放在类名后面。这个泛型可以有多个类型变量,如<T,U>

可以使用类定义的类型变量指定类中属性和方法的类型。

[java] view plain copy
 print?
  1. public class Pari<T> {  
  2.   
  3.     private T first;  
  4.     private T second;  
  5.       
  6.     public Pari(){  
  7.         first = null;  
  8.         second = null;  
  9.     }  
  10.     public Pari(T first,T second){  
  11.         this.first = first;  
  12.         this.second = second;  
  13.     }  
  14.       
  15.     public T getFirst(){  
  16.         return first;  
  17.     }  
  18.       
  19.     public T getSecond(){  
  20.         return second;  
  21.     }  
  22.       
  23.     public void setFirst(T value){  
  24.         first = value;  
  25.     }  
  26.     public void setSecond(T value){  
  27.         second = value;  
  28.     }  
  29. }  

其实泛型类可以看做是普通类的工厂。

泛型方法

泛型方法既可以在普通类中,也可以在泛型类中,定义方式是在方法名前加<T> T,说明该方法是泛型方法

[java] view plain copy
 print?
  1. public static <T> T getText(T param){  
  2.         return param;  
  3.     }  

类型变量的限定

有的时候,比如对于特定的方法执行特定的操作,但是该操作不适用于一些类型,这时可以对类型变量T设置限定,可以使其集成特别的类或者接口(没错,在这里对于接口也是使用继承,因为使用extends更加接近子类的意思),一个类型变量或通配符可以有多个限定

比如:T extends Comparable & Srializable

[java] view plain copy
 print?
  1. public static <T extends Comparable> Pari<T> getMinMax(T[] word){  
  2.       
  3.     if(word == null || word.length == 0)  
  4.         return null;  
  5.     T min = word[0];  
  6.     T max = word[0];  
  7.     for(int i=1;i<word.length;i++){  
  8.         if(word[i].compareTo(max) > 0)  
  9.             max = word[i];  
  10.         if(word[i].compareTo(min) < 0)  
  11.             min = word[i];  
  12.     }  
  13.     return new Pari<T>(min,max);  
  14. }  

注意:

JVM中没有泛型,只有普通的类和方法

所有的类型参数都是用他们的限定类型转换(如果没有类型参数,则使用Object类型),这个过程称为擦除(erased),擦除类型变量,并替换为限定类型

有时为保持类型安全性,需要插入强制类型转换


约束和局限性

不能用基本类型实例化类型参数

不能用类型参数代替基本类型:因此Pari<double>是错误的,需要使用pari<Double>,原因是类型擦除,擦除之后为Object类型,object类型并不能存储double值

类型查询只适用于基本类型

虚拟机中的对象总有一个特定的非泛型类型。因此,所有类型查询只产生原始类型。

如:if(a instanceof Pari<T>)是错误的,因为只能查询原始类型,即Pari

又如:

Pari<String> pari1 = ...

Pari<Employee> pari2 =...

if (pari1.getClass() == pari2.getClass())返回true,因为两次getClass()都是返回Pari.class

不能创建参数化类型数组

不能实例化参数类型数组

Pari<Sting>[] table = new Pari<String>[10];

因为当类型擦除后,为Pari[]类型,即可以转化为Object[]类型,这时候如果 table[0] = new Pari<Employee>();这时候就会抛出ArrayStoreException异常,所以,不允许创建参数类型数组。但是可以声明。如果想要实现可以使用通配类型数组然后进行强制类型转换

Pari<String>[] table = (Pari<String>[]) new Pari<?>[10];

不能实例化类型变量

new T()或者T.class这些都是非法的,因为类型擦除后为new Object(),这并不是想要的。

[java] view plain copy
 print?
  1. public Pari(){  
  2.      first = new T();  
  3.      second = new T();  
  4. }  

但是可以通过反射调用Class.newInstance方法构造

[java] view plain copy
 print?
  1. public static<T> Pari<T> makePari(Class<T> c){  
  2.      return new Pari<>(c.newInstance(),c.newInstance())  
  3. }  

泛型类的静态上下文中类型无效

[java] view plain copy
 print?
  1. public static class Singleton<T>{  
  2.      public static T s1;  
  3.      public static getS1(){  
  4.          return  s1   
  5.      }  
  6. }  
注意只是在静态类中不可以使用,普通类中可以使用。

不能抛出或捕获泛型类的实例

public class Problem<T> extends Exception{}是不对的。但是可以在异常规范中使用类型变量,意思就是可以在抛出异常的方法中使用类型变量 


泛型类继承规则

泛型类允许继承或者扩展其他的泛型类,如ArrayList<T>类实现List<T>接口,即一个ArrayList<Manager>可以被转换为List<Manger>。

但是ArrayList<Manager>不能够实现ArrayList<Employee>或List<Employee>。

所以记住,泛型的继承实现,需要保证其类型参数的一致。


通配符类型

固定的泛型类型系统,存在很多的局限性,为了解决这一点,引入了:通配符类型。

带有子类型的限定

[java] view plain copy
 print?
  1. Pari<? extends Employee>  
表示任何泛型Pari类型,他的类型参数是Employee的子类,如Pari<Manager>,当使用了通配符泛型,就可以将Pari<Manager>,给以这个Pari<? extends Employee>参数的函数了。

通配符的超类型限定

通配符限定与类型变量限定十分类似,但是可以指定一个超类型限定。

? super Manager

这个通配符限定了Manager的所有的超类,这与上面讲的通配符继承恰恰相反,这时候Pari<Employee> 或者Pari<Object>可以实现或者继承Pari<? super Manager>

带有超类型限定的通配符可以向泛型对象写入,带有子类型限定的通配符可以从泛型对象读取。

需要注意,通配符不是类型变量,不能像之前的泛型类型参数一样定义变量或者方法

? t = p.getFirst()这是错误的。

原创粉丝点击