深入解读泛型


泛型的本质:

泛型就是广泛的类型,就是在不同类型之间都可以使用的就叫做泛型,使用的是类型里面的方法,所以如果要使用泛型就需要保证使用泛型的类需要有共同的方法,泛型(generics,genericity)又称为“参数类型化(parameterized type)”或“模板(templates)”,是和继承(inheritance)不同而互补的一种组件复用机制。
继承和泛型的不同之处在于——在一个系统中,继承层次是垂直方向,从抽象到具体,而泛型是水平方向上的。当运用继承,不同的类型将拥有相同的接口,并获得了多态性;当运用泛型,将拥有许多不同的类型,并得以相同的算法作用在它们身上。因此,一般说来,当类型与实现方法无关时,使用泛型;否则,用继承,既然如此可以更进一步的总结为,使用泛型的类之间它们应该有共同的方法,否则泛型也就没有意义了。

而且本身泛型的T这个字符因为代表的是Object类型,所以任何的关于Object类型可以使用的方法和参数它都可以使用。

泛型类的本质是:让泛型类里面的类类型的参数可识别化(在真正使用的时候需要指定参数类型)。

泛型方法的本质是:让泛型方法里面的类类型参数可识别化(在真正使用的时候需要指定参数类型)。

泛型接口的本质是:让泛型接口里面的类类型参数可识别化(在真正使用的时候需要指定参数类型)




学习java或者软件开发的出去编程有时候项目经理经常会问到有关泛型的理解;

泛型:是指在定义类或者接口的时候可以为类和接口指定类型形参,在定义变量、定义方法是该类型形参可以当做普通的类型来使用,并且该类型形参在定义变量和创建对象的确定

1、定义泛型类,程序实例代码如下:


[java]  view plain copy
  1. public class GenericClass<E> {  
  2.     /** 
  3.      * @param args 
  4.      * 自定义泛型类 
  5.      */   
  6.     private E e;//变量  
  7.       
  8.     public GenericClass(){  
  9.           
  10.     }     
  11.     public GenericClass(E e){  
  12.         this.e=e;  
  13.     }     
  14.     public E getE(){//返回值类型  
  15.         return e;  
  16.     }     
  17.     public void println(E e){//函数参数  
  18.         System.out.println(e);  
  19.     }  
  20.     public static void main(String[] args) {  
  21.         GenericClass<Integer> gc=new GenericClass<Integer>();  
  22.         gc.println(1111111);  
  23.           
  24.         GenericClass<String> gc1=new GenericClass<String>();  
  25.         gc1.println("string");  
  26.                       
  27.     }  
  28. }  

2、实现泛型接口,在实现泛型接口或者类的时候,可以不指定类型形参,但是编译的时候会出现警告;

[java]  view plain copy
  1. public interface InterfaceGeneric<E> {          
  2.     public E getE();  
  3.     public void save(E e);    
  4. }  
[java]  view plain copy
  1. public class InterfaceImplement implements InterfaceGeneric<Integer>{  
  2.     /** 
  3.      * @param args 
  4.      */  
  5.     @Override  
  6.     public Integer getE() {  
  7.         // TODO Auto-generated method stub  
  8.         return null;  
  9.     }  
  10.     @Override  
  11.     public void save(Integer e) {  
  12.         // TODO Auto-generated method stub  
  13.           
  14.     }  
  15.     public static void main(String[] args) {  
  16.         // TODO Auto-generated method stub  
  17.           
  18.     }  
  19. }  

3、类型通配符

在定义一个方法的时候,如果该方法的参数为集合形参,集合的元素类型是不确定的,那我们该怎么定义呢?

假如如下所示的定义:


[java]  view plain copy
  1. //  public void println(List<Object> list){//函数参数  
  2. //      int count=list.size();  
  3. //      for(int i=0;i<count;i++){  
  4. //          System.out.println(list.get(i));  
  5. //      }  
  6. //  }  
[java]  view plain copy
  1. List<String> list=new ArrayList<String>();  
  2. list.add("a");    
  3. //println(list);不正确,因为List<String>不是List<Object>的子类  

那么这样的使用方法是不正确的,因为函数的形参是List<Object>类型的,而实参是List<String>类型的,但是需要注意的一点是List<String>并不是List<Object>的子类,所以这样写是不正确的,那么在这个list里的元素类型不确定的情况下怎么定义这个函数呢,这就用到了类型通配符;在java中类型通配符是一个?;类型通配符是所有泛型List的父类,在定义函数的时候用?代替类型,就可以在以后使用的时候定义各种各样的类型的List集合,如下的程序实例所示:


[java]  view plain copy
  1. public void println(List<?> list){//函数参数List使用类型通配符  
  2.         int count=list.size();  
  3.         for(int i=0;i<count;i++){  
  4.             System.out.println(list.get(i));  
  5.         }  
  6.     }  
  7.           
  8.   
  9. List<String> list=new ArrayList<String>();  
  10. list.add("a");        
  11. gc.println(list);  

4、类型通配符上限

定义一个形状类,有一个画图的方法,可以画各种各样的形状,则可以定义为接口如下所示:


[java]  view plain copy
  1. public interface Shape {  
  2.     public void draw();  
  3. }  

定义一个圆类和矩形类,分别实现上面定义的接口,然后重写方法draw();


[java]  view plain copy
  1. public class Rectangle implements Shape {  
  2.   
  3.     @Override  
  4.     public void draw() {  
  5.         // TODO Auto-generated method stub  
  6.         System.out.println("draw a rectangle");  
  7.     }  
  8.   
  9. }  
  10. public class Circle implements Shape {  
  11.   
  12.     @Override  
  13.     public void draw() {  
  14.         // TODO Auto-generated method stub  
  15.         System.out.println("draw a circle");  
  16.     }  
  17.   
  18. }  

假如有一个画布可以画很多图形,则可以这样定义该画布类:


[java]  view plain copy
  1. public class Canves {  
  2.     /** 
  3.      * @param args 
  4.      */  
  5. //这里使用List<Shape>不正确,会出现编译错误,因为List<Circle> List<Rectangle>不是List<Shape>的子类  
  6. //  public void draw(List<Shape> shapeList){  
  7. //        
  8. //  }  
  9.       
  10.     /* 
  11.      *可以考虑使用类型通配符的方式List<?> 
  12.      *但是这里使用的类型通配符是配的所有的类型,所以加进去的元素就是Object类型的 
  13.      *这里需要强制类型转换,降低了程序的执行效率;所以可以使用java提供的类型通配符的上限定义方法 
  14.      **/  
  15. //  public void draw(List<?> shapeList){  
  16. //      for(Object obj:shapeList){  
  17. //          Shape shape=(Shape)obj;  
  18. //          shape.draw();   
  19. //      }  
  20. //  }  
  21.     /* 
  22.      *这里使用类型通配符的上限的形式定义list集合的元素类型List<? extends Shape> 
  23.      * */  
  24.     public void draw(List<? extends Shape> shapeList){  
  25.         for(Shape shape:shapeList){           
  26.             shape.draw();  
  27.         }  
  28.     }  
  29.       
  30.     public static void main(String[] args) {          
  31.         Canves c=new Canves();  
  32.         List<Circle> listCircle=new ArrayList<Circle>();  
  33.         listCircle.add(new Circle());  
  34.           
  35.         List<Rectangle> listRectangle=new ArrayList<Rectangle>();  
  36.         listRectangle.add(new Rectangle());  
  37.           
  38.         c.draw(listCircle);//   1  
  39.         c.draw(listRectangle);//    2  
  40.     }  
  41. }  


 

draw()方法的参数里list集合的类型使用的是类型通配符的上限形式,这样既可以往list集合中添加不同的Shape类子类的对象,而且不用进行强制类型转换。

5、泛型方法

泛型方法的使用效果和类型通配符非常相似


[java]  view plain copy
  1. public class GenericMethod {  
  2.     //泛型方法  
  3.     public <E> void genericmethod(List<E> a){  
  4.           
  5.         for(E t:a)  
  6.             System.out.println(t.toString());  
  7.           
  8.     }  
  9.           
  10.     public static void main(String[] param){  
  11.         List<String> list=new ArrayList<String>();  
  12.         list.add("dfd");  
  13.         list.add("dfd");  
  14.         list.add("dfd");  
  15.         list.add("dfd");  
  16.         new GenericMethod().genericmethod(list);  
  17.           
  18.         List<Integer> list1=new ArrayList<Integer>();  
  19.         list1.add(1);  
  20.         list1.add(2);  
  21.         list1.add(3);  
  22.         list1.add(4);  
  23.         new GenericMethod().genericmethod(list1);                 
  24.     }     
  25. }  




[java]  view plain copy
  1. public static <T> T get(T t1,T t2) {    
  2.             if(t1.compareTo(t2)>=0);//编译错误    
  3.             return t1;    
  4.   
  5. }  

很明显会出现编译错误,因为泛型的类型不确定,根本找不到我们调用的方法。可是如果我定义的泛型类里的泛型方法就是要把比较写好呢,这样子类不是就不用重写了吗,怎么办呢,用类型限定吧。就是说T没有我们想要的方法,那我们就让T继承有我们想要的方法的接口或者类。比如:


[java]  view plain copy
  1. public static <T extends Comparable> T get(T t1,T t2) { //添加类型限定    
  2.             if(t1.compareTo(t2)>=0);    
  3.             return t1;    
  4.   
  5. }  



2015-12-23 14:00:那么Java泛型中的T和?有什么区别呢,正如下面两个方法是一样的:


[java]  view plain copy
  1. public void printlns(List<?> list){//函数参数List使用类型通配符,泛型方法  
  2.        int count=list.size();    
  3.        for(int i=0;i<count;i++){    
  4.            System.out.println(list.get(i));    
  5.        }    
  6.    }  
  7.   
  8. public <T> void println(List<T> list){//函数参数List使用类型通配符,泛型方法  
  9.     int count=list.size();    
  10.     for(int i=0;i<count;i++){    
  11.         System.out.println(list.get(i));    
  12.     }    
  13. }  

你可能感兴趣的:(泛型)