分享
 
 
 

J2SE5.0 实例---泛型

王朝java/jsp·作者佚名  2006-01-31
窄屏简体版  字體: |||超大  

泛型简介

泛型其实并不是一种新的语言元素,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的一个子类,但是具体它是哪种子类我们又不必关心,所以方法中使用了泛型作为一个类型参数,同时也用了统配类型作为第二类型参数

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有