泛型总结

1. 为什么要使用泛型
   因为
   1)使用泛型意味着编写的代码可以被很多个不同类型的对象所重用。
   2)使用泛型之后可以减少类型转换的风险
  
2.泛型类
  1) 类定义中的类型变量指定了方法的返回类型以及域和局部变量的类型。
  2) 在生成泛型类的实例时,没有强制要求要去设置其类型参数,只是不设置类型参数时,会给出警告:
   如"Test is a raw type. References to generic type Test<T> should be
  parameterized"
 
3.泛型方法
  1) 泛型方法可以定义在普通类中,也可以定义在泛型类中
  2)泛型方法的调用,有2种方式,一般使用第2种方式。如:
    //1. 在方法前加上<String>
  ArrayAlg.<String>getMiddle(names);
  //2. 在方法不加上<String>,编译器会推断出T的类型是String,这样调用也不会有警告提示
  ArrayAlg.getMiddle(names);

4.泛型限定
  1)目的: 使用泛型边界控制(泛型限定)是为了使用T上的方法,如果不限定则不能调用T上的任何代码。
  例:T extends Comparable 表明T只能是实现了Comparable接口的类或者接口。这是对泛型边界的控制。
 这时就可以调用T上的compareTo方法,因为编译器知道T实现了omparable接口。
  2)一个类型变量可以有多个限定,如:
   T extends Comparable & Serializable,多个限定之间使用&分割。
  3)跟java的继承一样,对泛型的限定只能有一个是限定类,可以多个限定接口,并且限定类必须放在类型变量的
   限定中的第一个
   如:T extends boundTypeClass1 & inteface1 & interface2
   如果是  T extends boundTypeClass1 & boundTypeClass2 则会报错

5.泛型代码与虚拟机
  1)虚拟机没有泛型类型对象,所有的对象都是普通对象。如,没有ArrayList<String>.class 和ArrayList<Integer>.class
   的区别,二者在虚拟机中都是Arraylist.class.即泛型类型的信息在jvm中被擦除了(也即类型参数被擦除)。 泛型的信息只能在.java文件中看到,jvm编译后的.class文件中没有泛型的信息。
  2)当定义一个泛型类型时, jvm都会自动地为该泛型提供一个相应的原始类型(raw type).原始类型的名字就是删除类型参数后的
   泛型类型名。如:Pair<String>的原始类型就是Pair.
  3)在jvm中,泛型类型变量会被擦除,并替换为限定类型,如果没有指定限定类型,在替换为Object。如Pair<T>,因没有指定限
   定类型,所以类Pair中所有的T会被替换成Object. 如 方法 public T getFirst(){return first} 会被替换成public Object getFirst(){return first}. 
   如果指定了限定,那么原始类型会用第一个限定类型的变量来替换。如:
   public class Interval<T extends Comparable & Serializable> implement Serializble{
    public Interval(T first , T second){
      ....
    }
    private T lower;
    private T upper;
   }
   原始类型Interval替换后如下(也即类中的T被第一个泛型限定Comparable替换):
   public class Interval implement Serializble{
    public Interval(Comparable first , Comparable second){
      ....
    }
    private Comparable lower;
    private Comparable upper;
   }
 
6. 将泛型变量赋给普通变量和把普通变量赋给泛型变量的问题。

    Thinking in javaP395, 泛型对象赋给普通对象,不会有警告,但是把普通对象赋给泛型对象会有警告。
7. java泛型需要考虑的一些限制
 1) 不能用基本类型实例化参数类型。如没有Pair<double>,只有Pair<Double>.
 2) 运行时类型查询只使用于原始类型。如if(a  instanceof Pair<String> ) 跟if(a  instanceof Pair) 是一样的
 3) 参数化数组不合法。如 Pair<String>[] ps = new Pair<String>[10]; //error
       但是在方法返回的时候可以返回 T[];
 4) 不能实例化类型变量
      如: new T() 或 T.class;//error.  
 5) 泛型类的静态上下文中类型变量无效。
    如声明一个 public static T getxxx(){}的方法会报错。    
8. 泛型的协变和逆变,即: <T extends SomeType > 和<T super SomeType>

   1)协变和逆变的作用:

       是在两个泛型之间建立某种类型的向上转型关系。因为普通类的继承关系直接在泛型中使用是行不通的。

       如:Number 是Integer 的父类。Number n  = new Integer();这种使用方式没有问题,但是如果有一个泛型接口

       public interface Box<T> {
          public T get();
          public void put(T element);
          public void put(Box<T> box);
       }

       注:BoxImpl代码省略
      Box<Integer> iBox = new BoxImpl<Integer>(3);
      Box<Number> nBox = iBox;

      上面的语句会报错。但是使用

      Box<? extends Number> nBox  = iBox; 就可以了。

 2)注意事项:
     协变只能取数据,不能set数据。因为取出来的数据,至少是Number。

而Box<? extends Number> nBox  = new BoxImpl<Integer>(3); 也可以赋值为

Box<? extends Number> nBox  = new BoxImpl<Double>(3), 所以设置值时,编译器不知道是Integer,还是 Double,故设置值出错。

而逆变则相反,可以设置数据,不能用于取数据


9. 无界通配符<?>
 1)为什么要用无界通配符?
 个人感觉用处不大,唯一能体会到的用处是:在使用遗留代码或者一些第3方工具类的时候,去掉非泛型代码的警告。如
 Query query = "";
 List resultList = query.getResultList();
 该句会有警告。因为getResultList不是泛型化的List,但是可以使用以下语句来去除警告:
 List<?> resultList = query.getResultList();
    
 10. 类继承中的泛型, 只能使用下面的几种方式来声明。

 class Myclass<T> extends Base<T> // 同时声明T

 class Myclass extends Base<String> //父类确定类型

 class Myclass extends Base //都不声明类型。

 


 
 
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值