|
![]() |
名片设计 CorelDRAW Illustrator AuotoCAD Painter 其他软件 Photoshop Fireworks Flash |
|
泛型简介 泛型其实并不是一种新的语言元素,C++中早就就有,但是在C++之后的java却没有吸收这个特性,现在Java也有了泛型的特性,大概也和.Net的竞争有关系吧。 首先看泛型的一个应用。 在过去,我们可能常常要写一些类似这样的代码: List stringList=new LinkedList(); stringList.add("firstString"); stringList.add("secondString"); String str=(String)stringList.iterator().next(); 实际上第三行对String的类型转变意义并不大,因为通常我们假如在操作一个List,都是知道这个List里面放的是什么类型对象的,但是我们假如不这样写又通不过语法检查。 利用java的泛型机制,我们可以这么写: List<String> stringList=new LinkedList<String>(); stringList.add("firstString"); stringList.add("secondString"); String str=stringList.iterator().next(); 这样做的好处是在定义容器的时候就指明了容器中的类型,一方面我们不再需要取一个元素时候做强制类型转变,另外一方面假如在这个容器中放入的对象类型不符合要求,那么会在编译时候产生一个错误,而不是在运行时候才抛出一个非常。 另外这样也提高了程序的可读性。 泛型类型的定义 下面是一个简朴的使用泛型类的定义: public class MyGenericClass<T> { private T value; public T getValue() { return value; } public void setValue(T value) { this.value = value; } } 值得注重的一点是,静态变量不能够使用泛型定义,也就是说类似下面的语句是非法的: public class MyGenericClass<T> { public static T value;//错误的定义 } 此外,泛型的定义不会被继续,举个例子来说,假如A是B的子类,而C是一个声明了泛型定义的类型的话,C<A>不是C<B>的子类。为了更好的说明,可以看下面的代码,这段代码是错误的。 List<String> strList =new ArrayList<String>(); List<Object> objList=strList; //错误的赋值 不过这样一段代码是准确的: List<Object> strList =new ArrayList<Object>(); strList.add("jsdkfjsdl"); 统配类型 假设我们需要这样一个函数,使用它可以把一个集合中所有的元素打印出来,在以前我们可能这样定义: void printCollection(Collection c) { Iterator i = c.iterator(); for (k = 0; k < c.size(); k++) { System.out.println(i.next()); } } 使用新的泛型特性我们可能会这样写: void printCollection(Collection<Object> c) { for (Object e : c) { System.out.println(e); } } 但是这样有一个问题,如果我们现在有个对象类型是Collection<String>,那么我们不能够将它作为参数传给printCollection,因为Collection<String>并不是Collection<Object>的子类。 为了解决这个问题,我们可以使用统配类型?,也就是定义成下面这个样子: void printCollection(Collection<?> c) { for (Object e : c) { System.out.println(e); } } 可以说Collection<?>是所有Collection的父类。 再来看一段下面的代码 private void clearAllMaps(Collection<Map> c) { for(Map m:c) { m.clear(); } } 毫无疑问,它也存在上面我们所说的问题,也就是对HashMap之类Map的子类无法进行操作,但是假如我们将参数改成Collection<?>又不大合理,因为我们只希望对父类为Map的子类进行操作,那么我们可以这样改写: private void clearAllMaps(Collection<? extends Map> c) { for(Map m:c) { m.clear(); } } 类似于? extends Map之类的统配符称为限定统配类型。 假设一个对象h类型为Collection<HashMap>,那么我们将h作为参数传给clearAllMaps,如下面一段代码所示: List<HashMap<String,String>> h=new ArrayList<HashMap<String,String>>(); HashMap<String,String> m=new HashMap<String,String>(); m.put("key","value"); h.add(m); clearAllMaps(h); 对于在类似于上面所说,使用了? extend XXX的方式,值得注重的一点是不能够在方式体内用XXX的子类对象作为代替。如下面一段代码是错误的: public void addRectangle(List<? extends Shape> shapes) { shapes.add(0, new Rectangle()); // 错误用法! } 这里我们假设Rectangle是Shape的一个子类。 不答应这样写的原因比较简朴,因为调用该方式时候参数类型可能是Shape的另外一个子类。如果说Shape除了Rectangle这个子类以外还有另外一个子类Circle,那么我们可以把一个List<Circle>类型的对象作为参数传给这个方式(注重这样是合法的),而在方式体内却把一个Rectangle对象放到了shapes里面,这显然是不合理的。 除了extends,在泛型参数类型中还可以使用super要害字,参照下面一段程序: private void addString(Collection <? super String> c) { c.add("a String"); } 泛型函数 我们在前面提到了统配类型,现在让我们来设想一个函数,它实现这样的功能,将一个数组中的元素添加到一个Collection中,为了保证程序的通用性,我们可能会写出另外一段错误的代码: private void fromArrayToCollection(Object[] a, Collection<?> c) { for (Object o : a) { c.add(o); // 错误的代码 } } 那么这个函数应该怎么写呢?我们可以通过对函数添加泛型参数的方式实现,如下面所示: private <T> void exfromArrayToCollection(T[] a, Collection<T> c) { for (T o : a) { c.add(o); //这样是准确的 } } 那么,在什么时候我们应该使用统配类型,什么时候我们应该使用泛型函数呢?答案是取决于函数参数之间,函数参数和返回值之间的类型依靠性。 假如一个函数的参数类型与函数返回的参数没有必然关联,同时对于该函数其他的参数的类型也没有依靠关系,那么我们就应该使用统配符,否则就应该使用泛型函数。 为了更清晰地说明这一点,我们可以看一下java.util包中Collections类型几个方式的定义: class Collections { static void swap(List<?> list, int i, int j) {...} static <T> void copy (List<? super T> dest, List<? extends T> src) {...} } 其中swap函数实际上也可以这样定义: static <T>void swap(List<T> list, int i, int j) {...} 但是注重到这里泛型类型参数T只在参数中用到了一次,也就是说它和函数其他部分没有依靠性,这可以看作是我们应该使用?的一个标志。 copy方式中,拷贝源src中的元素必须是dest所能够接受的,src中的元素必须是T的一个子类,但是详细它是哪种子类我们又不必关心,所以方式中使用了泛型作为一个类型参数,同时也用了统配类型作为第二类型参数 返回类别: 教程 上一教程: 一个FIFO pipe的简朴Java实现 下一教程: [Eclipse笔记]Eclipse真的是商用IDE的杀手吗? 您可以阅读与"J2SE5.0 实例---泛型"相关的教程: · J2SE5.0 实例---变长参数 · J2SE5.0实例---注释(annotation) · jsp源码实例5(cookie) · JSP应用程序开发中安全问题的实例解析 · webwork2+FreeMarker 制作数据列表显示简朴实例 |
![]() ![]() |
快精灵印艺坊 版权所有 |
首页![]() ![]() ![]() ![]() ![]() ![]() ![]() |