泛型总结

  1. 云栖社区>
  2. 博客>
  3. 正文

泛型总结

晓生寒 2019-03-23 15:31:30 浏览435
展开阅读全文
泛型

参与了孤尽大大的DIY班,这一期的主题时泛型,之前没有深入研究过泛型,于是有了此篇的总结。

1.简单的泛型类和接口
    public class GenericMemoryCell<AnyType>{
        public AnyType read(){
            return storedVal;
        }
        public void write(AnyType x){
            storedVal = x;
        }
        
        private AnyType storedVal; 
    }
    public interface Comparable<>{
        public int comparaTo(AnyType other);
    }
从基础的泛型可以看出,限制了类和接口的参数的类型。这样一个直接的好处就是,时以前只有在运行时报告的错误,如今现在可以在编译时报错。
2.菱形运算符
    //通过<>可以省略,自动匹配要生成的类的type
    GenericMemoryCell<Integer> m=new GenericMemoryCell<>();
3.带有限制的通配符

现在场景:totalArea是一个计算图形面积的静态方法,Shape是一个父类,Square,Circle继承了Shape的父类。

    public static double TotalArea(Colletion<Shape> arr){
        double total=0;
        for(Shap s:arr){
            if(s!=null)
                total+=s.area();
        }
        return total;
    }

问题是,如果是,方法中传入,Colletion。编译通过,但是产生运行时错误。为了解决这个问题,java5采用了通配符表示参数类型的子类或者超类。Collection ,T IS-A Shape 。

    public static double TotalArea(Colletion<?extends Shape> arr){
        double total=0;
        for(Shap s:arr){
            if(s!=null)
                total+=s.area();
        }
        return total;
    }
4.泛型方法

定义泛型方法时,必须在返回值前边加一个,来声明这是一个泛型方法,持有一个泛型T,然后才可以用T作为方法返回值
泛型方法要求的参数是Class类型,而Class.forName()方法的返回值也是Class,因此可以用Class.forName()作为参数。其中,forName()方法中的参数是何种类型,返回的Class就是何种类型。在本例中,forName()方法中传入的是User类的完整路径,因此返回的是Class类型的对象,因此调用泛型方法时,变量c的类型就是Class,因此泛型方法中的泛型T就被指明为User,因此变量obj的类型为User。
当然,泛型方法不是仅仅可以有一个参数Class,可以根据需要添加其他参数。
为什么要使用泛型方法呢?因为泛型类要在实例化的时候就指明类型,如果想换一种类型,不得不重新new一次,可能不够灵活;而泛型方法可以在调用的时候指明类型,更加灵活。

   public static <T> boolean contains(T [] arr,T x){
        for(T val:arr){
            if(x.equals(val))
                return true;
        }
        return false;
    }
5.类型界限

我们想编写一个finMax的程序,比较的AnyType必须是实现comparable才可以比较。下面的这种方法是不行的

   public static <AnyType> AnyType findMax(AnyType [] arr){
       int maxIndex=0;
       for(int i=0;i<arr.length;i++){
           if(arr[i].compareTo(arr[maxIndex]))
               maxIndex=i;
       }
       return arr[maxIndex];
   }

改写泛型,需要比较的泛型是可以比较的。所以就有
public static >
假设Shape实现了Comparable,Square继承了Shape,Square所继承的泛型是Comparable,并不是Comparable,但是这样也是可以的。所以,可以写成以下格式:

   public static <AnyType extends Comparable<? super AnyType>> AnyType findMax(AnyType [] arr){
       int maxIndex=0;
       for(int i=0;i<arr.length;i++){
           if(arr[i].compareTo(arr[maxIndex]))
               maxIndex=i;
       }
       return arr[maxIndex];
   }
6.类型擦除

因为,泛型是java语言中的成分,而不是虚拟机中的结构。所以泛型类需要经过虚拟机的类型擦出而变成非泛型类。

编译器生成一个与泛型类名相同的原始类。类型变量使用它们原先的类型界限来代替。
7.对于泛型的限制

由于类型擦除的存在,所以必须遵从以下规则:
1.基本类型不能做类型参数
2.instanceof检测和类型转换工作只对原始类型进行。

       这句话的理解,就是编译时检测,只对原始类型有用,进行转换之后就不管用了。
   GenericMemoryCell<Integer> cell1=new GenericMemoryCell<>();
   cell1.write(4);
   Object cell=cell1;
   GenericMemoryCell<String> cell2=(GenericMemoryCell<String>) cell;
   String s=cell2.read;

3.在一个泛型类中,static方法和static域均不可引用类型变量,因为再类型擦出后,类型变量就不存在了。
4.泛型类型的实例化

    //非法,如果T是一个类型变量
      T obj=new T();
      T [] arr=new T[10]

5.参数化类型的数组

如下方案例,正常情况,存在类型检查,但是类型擦除之后,cell和数组arr里面的内容同样都是GenericMemoryCell。只有在实际存储的时候会出现,ClassCastException错误。
   GenericMemoryCell<String> [] arr= new GenericMemoryCell<String> [10];
   GenericMemoryCell<Integer> cell1=new GenericMemoryCell<>();
   cell1.write(4);
   Object [] arr2=arr;
   arr2[0]=cell
   String s=arr2[0].read();
8.函数对象

​ 定义一个没有数据而只有一个方法的类,并传递该类的一个实例。事实上,一个函数通过将其放在一个对象内部而被传递,这样的对象叫做函数对象。

   public static <T> T findMax(T [] arr,Comparator<? super T> cmp){
           int maxIndex=0;
           for(int i=0;i<arr.length;i++){
               if(cmp.compare(arr[i], arr[maxIndex])>0)
                   maxIndex=i;
           }
           return arr[maxIndex];
    }
   class CaseInsensitiveCompare implements Comparator<String>{
       public int compare(String lhs,String rhs){
           return lhs.compareToIgnoreCase(rhs);
       }
   }
   class TestProgram{
       public static void main(String [] args){
           String [] arr={"ZEBRA",“ali”,"arc"}
           System.out.println(findMax(arr,new CaseInsensitiveCompare()));
       }
   }
   //输出:ZEBRA最后

网友评论

登录后评论
0/500
评论
晓生寒
+ 关注