java 泛型(一)

来源:互联网 发布:知乎变成蛤乎了 编辑:程序博客网 时间:2024/03/29 08:32


  • 什么是泛型?什么是原生类型(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
原创粉丝点击