java 泛型(一)



  • 什么是泛型?什么是原生类型(raw type)?
声明中具有一个或多个类型参数(type parameter)的类或者接口就是泛型类或者泛型接口。
泛型类和泛型接口同称为泛型。
每个泛型都有一个原生类型(raw type),既不带任何类型参数的泛型,原生类型与java没有泛型之前的接口是一样的。
List<E>和List(raw type)


  • 为什么使用泛型?
    1. 代码复用
    2. 编译时的类型检查:编译器会对使用泛型的代码进行类型检查,如果违反了类型,安全编译器会抛出警告,编译时发现错误要比运行时发现错误好的多。
    3. 消除转型

没有使用泛型:

List list = new ArrayList();
String s = (String) list.get(0);
list.add("hello");

使用泛型:

List<String> list = new ArrayList<String>();
list.add("hello");
String s = list.get(0); // no cast



我们来对比一下java 1.5之前没有泛型和又了泛型之后的差别:




//java 1.5之前
//class Stamp{}
//class Coin{}
private final Collection stamps=...
stamps.add(new Coin());// 通过编译,并且不会出现错误提示,只会警告你,但警告有可能被忽略

//直到从stamps获取coin时,才会收到错误提示
for(Iterator i=stamps.iterator();i.hasNext()){
Stamp s=(Stamp)i.next(); //抛出ClassCastException
}

    
//有了泛型之后
private final Collection<Stamp> stamp=...
stamp.add(new Coin()); // 报错:add(Stamp) can not be applied to Coin;

那么问题来了,如果不提供参数类型,使用集合类和其他泛型类也是合法的,但是不应该这么做,原因:

如果使用原生类型,就失去了泛型在安全性和表述下方面的优势。


既然如此,为什么还有原生类型存在呢?这是为了提供兼容性,其实就是保持没有使用泛型(java 1.5之前)的java代码的合法性。


这里还有一个特殊的情况需要强调一下:List<Object>
不严格的说,原生类型List逃过了编译检查,而List<Object>告诉编译器,它能够持有任何对象。

List l1 = new List<String>();  //合法
List<Object> l2 = new List<String> // 不合法 Incompatible types

因此使用List会丢失安全性,但是List<Object>则不会
举例:

原生类型可以通过编译,但是收到了一条警告。

public static void main(String args []){
       List<String> l=new ArrayList<String>();
       safeAdd(l,3);
   }

   public static void safeAdd(List list, Object obj){
       list.add(obj); //Unchecked call to 'add(E)' as a member of raw type
   }


使用List<Object>,编译器提示错误。

public static void main(String args []){
        List<String> l=new ArrayList<String>();
        safeAdd(l,3); // 报错
   }
   public static void safeAdd(List<Object> list, Object obj){
       list.add(obj);
   }

  • 无限制的通配符类型。如果我不想使用泛型,但是又想确保类型安全该怎么办?


这是由上面的最后例子引出的一个问题。有时候可能我们不在乎或者不确定集合中的元素类型,该怎么办?

  • 我们可以使用原生类型,但是有什么坏处?如果不知道 ,再看看上面的例子。
//use of raw type for unknown element type -- don't do this
    static int numElementInCommon(Set s1,Set s2){
       int result=0;
       for(Object o1:s1){
           if(s2.contains(o1))
               result++;
       }
       return result;
    }

  • java 1.5发型版开始提供了更安全的替代方法,即无限制的通配符类型(unbounded wildcard type)
某个类型的集合,只是我不关心或者不确定时什么集合,Set<?> 这是普通的参数化Set类型,可以持有任何集合。
  static int numElementInCommon(Set<?> s1,Set<?> s2){
       int result=0;
       for(Object o1:s1){
           if(s2.contains(o1))
               result++;
       }
       //s1.add(null);
       //s1.add(1);   //报错
       return result;
   }

那么无限制的通配符安全在哪呢?它只允许加入null,其他类型的都不可以。

这虽然不是很令人满意,但是编译器已经尽到它的职责,防止你破坏集合的类型约束。如果无法接受这些限制,可以使用泛型方法后者有限制的通配符(bounded wildcard type)


  • 下面两种例外可以不使用泛型:
instanceof: 与泛型信息在运行时擦除有关
class literal:List.class而不是List<?>.class 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值