Java泛型

来源:互联网 发布:三线性优化 编辑:程序博客网 时间:2024/05/17 07:46

在java se1.5中,增加了一个新的特性:泛型(日本语中的总称型)。何谓泛型呢?通俗的说,就是泛泛的指定对象所操作的类型,而不像常规方式一样使用某种固定的类型去指定。泛型的本质就是将所操作的数据类型参数化,也就是说,该数据类型被指定为一个参数。这种参数类型可以使用在类、接口以及方法定义中。

一、为什么使用泛型呢?

在以往的j2se中,没有泛型的情况下,通常是使用object类型来进行多种类型数据的操作。这个时候操作最多的就是针对该object进行数据的强制转换,而这种转换是基于开发者对该数据类型明确的情况下进行的(比如将object型转换为string型)。倘若类型不一致,编译器在编译过程中不会报错,但在运行时会出错。

使用泛型的好处在于,它在编译的时候进行类型安全检查,并且在运行时所有的转换都是强制的,隐式的,大大提高了代码的重用率。

二、泛型的简单例子:

首先,我们来看看下面两个普通的class定义

public class getstring {

private string mystr;

public string getstr() {

return mystr;

}

public void setstr(str) {

mystr = str;

}

}

public class getdouble {

private double mydou;

public double getdou() {

return mydou;

}

public void setdou(dou) {

mydou = dou;

}

}

这两个class除了所操作的数据类型不一致,其他机能都是相同的。现在,我们可以使用泛型来将上面两个class合并为一个,从而提高代码利用率,减少代码量。

public class getobj {

private t myobj ;

public t getobj() {

return myobj;

}

public void setobj {

myobj = obj;

}

}

那么,使用了泛型后,如何生成这个class的实例来进行操作呢?请看下面的代码:

getobj strobj = new getobj();

strobj.setobj(“hello nissay”);

system.out.println(strobj.getobj());

getobj douobj = new getobj();

douobj.setobj(new double(“116023”));

system.out.println(douobj.getobj());

三、例子分析

现在我们来分析上面那段代码:

1、是泛型的标记,当然可以使用别的名字,比如。使用声明一个泛型的引用,从而可以在class、方法及接口中使用它进行数据定义,参数传递。

2、在声明的时候相当于一个有意义的数据类型,编译过程中不会发生错误;在实例化时,将其用一个具体的数据类型进行替代,从而就可以满足不用需求。

四、泛型的规则和限制

通过上述的例子,我们简单理解了泛型的含义。在使用泛型时,请注意其使用规则和限制,如下:

1、泛型的参数类型只能是引用类型,而不能是简单类型。

比如,是不可使用的。

2、可以声明多个泛型参数类型,比如,同时还可以嵌套泛型,例如:>

3、泛型的参数类型可以使用extends语句,例如。

4、泛型的参数类型可以使用super语句,例如。

5、泛型还可以使用通配符,例如

五、扩展

1、extends语句

使用extends语句将限制泛型参数的适用范围。例如:

,则表示该泛型参数的使用范围是所有实现了collection接口的calss。如果传入一个则程序编译出错。

2、super语句

super语句的作用与extends一样,都是限制泛型参数的适用范围。区别在于,super是限制泛型参数只能是指定该class的上层父类。

例如,表示该泛型参数只能是list和list的上层父类。

3、通配符

使用通配符的目的是为了解决泛型参数被限制死了不能动态根据实例来确定的缺点。

举个例子:public class sampleclass{…}

假如a,b,c,…z这26个class都实现了s接口。我们使用时需要使用到这26个class类型的泛型参数。那实例化的时候怎么办呢?依次写下

sampleclass a = new sampleclass();

sampleclass a = new sampleclass();

sampleclass a = new sampleclass();

这显然很冗余,还不如使用object而不使用泛型,呵呵,是吧?

别着急,咱们使用通配符,就ok了。

sampleclass sc = new sampleclass();

只需要声明一个sc变量,很方便把!

通配符进阶

泛型最复杂的部分是对通配符的理解。我们将讨论三种类型的通配符以及它们的用途。

首先让我们了解一下数组是如何工作的。可以从一个integer[]为一个number[]赋值。如果尝试把一个float写到number[]中,那么可以编译,但在运行时会失败,出现一个arraystoreexception:

integer[] ia = new integer[5];

number[] na = ia;

na[0] = 0.5; // compiles, but fails at runtime

如果试图把该例直接转换成泛型,那么会在编译时失败,因为赋值是不被允许的:

list ilist = new arraylist();

list nlist = ilist; // not allowed

nlist.add(0.5);

如果使用泛型,只要代码在编译时没有出现警告,就不会遇到运行时classcastexception。

上限通配符

我们想要的是一个确切元素类型未知的列表,这一点与数组是不同的。

list是一个列表,其元素类型是具体类型number。

list是一个确切元素类型未知的列表。它是number或其子类型。

上限

如果我们更新初始的例子,并赋值给list,那么现在赋值就会成功了:

list ilist = new arraylist();

list nlist = ilist;

number n = nlist.get(0);

nlist.add(0.5); // not allowed

我们可以从列表中得到number,因为无论列表的确切元素类型是什么(float、integer或number),我们都可以把它赋值给number。

我们仍然不能把浮点类型插入列表中。这会在编译时失败,因为我们不能证明这是安全的。如果我们想要向列表中添加浮点类型,它将破坏ilist的初始类型安全——它只存储integer。

通配符给了我们比数组更多的表达能力。

为什么使用通配符

在下面这个例子中,通配符用于向api的用户隐藏类型信息。在内部,set被存储为customerimpl。而api的用户只知道他们正在获取一个set,从中可以读取customer。

此处通配符是必需的,因为无法从set向set赋值:

public class customerfactory {

private set _customers;

public set getcustomers() {

return _customers;

}

}

无界通配符

最后,list列表的内容可以是任何类型,而且它与list几乎相同。可以随时读取object,但是不能向列表中写入内容。

公共api中的通配符

总之,正如前面所说,通配符在向调用程序隐藏实现细节方面是非常重要的,但即使下限通配符看起来是提供只读访问,由于remove(int position)之类的非泛型方法,它们也并非如此。如果您想要一个真正不变的集合,可以使用java.util.collection上的方法,比如unmodifiablelist()。

编写api的时候要记得通配符。通常,在传递泛型类型时,应该尝试使用通配符。它使更多的调用程序可以访问api。

通过接收list而不是list,下面的方法可以由许多不同类型的列表调用:

void removenegatives(list list);

构造泛型类型

现在我们将讨论构造自己的泛型类型。我们将展示一些例子,其中通过使用泛型可以提高类型安全性,我们还将讨论一些实现泛型类型时的常见问题。

集合风格(collection-like)的函数

第一个泛型类的例子是一个集合风格的例子。pair有两个类型参数,而且字段是类型的实例:

public final class pair好文要顶关注我收藏该文与我联系


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/
原创粉丝点击