泛型
一、 什么是泛型
百度百科:泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安全简单。
就我个人来看,“泛型”可以看成是一张“空白的占位符”,当你需要什么类型的时候,就可以往白纸上填写自己需要的类型。就像方法的形式参数是运行时传递的值的占位符一样。
举个例子:
```
//此处T为随意写的
public class Genericity<T>{//这里的T就是泛型,是一个“空白的占位符”,T的类型由外部实体化的时候指定
private T key;
public Genericity( T key){
this.key = key;
}
public T getKey(){
return key;
}
}
当你进行实例化的时候:
Genericity<String>genericityString = new Genericity<String>(“hello,我是泛型”);
Syso(genericityString. getKey(););
输出结果:hello,我是泛型
这就是泛型的简单实例。
二、 为什么要用泛型(泛型的好处)
1. 提高代码复用性
为什么说提高了代码的复用性:
现在我们需要返回两个信息,一个是字符串类型,一个是整数数值类型的信息。
不用泛型的代码如下:
//返回字符串类型信息
public String getString(StringstringMessage){
return stringMessage;
}
//返回数值类型信息
public int getInt(int intMessage){
return intMessage;
}
使用泛型的代码:
public <T>TgetWord(T t){
return t;
}
这样,我们只需要这一个方法就能实现上面两个方法才能实现的任务,是不是简单了许多,而且扩展性更强。
2. 减少数据的类型转换,提高代码的运行效率;类型安全,因为泛型是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率
泛型是如何实现消除类型转换呢,先拿没有泛型之前来说起。
List集合里面可以添加各种数据类型和对象,就好比是个“大杂烩”。现在我们需要从这个list集合里面取出我们需要的数据,比如我们要一个String类型的数据,可是我们并不知道具体哪一个是String类型,随意取出一个,并且进行强制类型装换,就会出现错误,类型安全就会出现问题。
如下:
String str = "hello ha";
Tree tree = new Tree(); //自定义的类
List list = new ArrayList();
list.add(tree);//tree对象加入到list中
list.add(str);
String string = (String) list.get(0);
System.out.println(string);
执行后会报错:
Exception inthread "main" java.lang.ClassCastException:
* genericity_Type.Treecannot be cast to java.lang.String
atgenericity_Type.Animal.main(Animal.java:18)
这就是类型装换失败,而且在编译的时候不会报错,让你不知不觉中陷入了类型安全错误。
泛型是如何来避免这个类型安全错误呢?就像这样:
String str = "helloha";
Tree tree = new Tree(); //自定义的类
List<String> StringList = new ArrayList<String>();
StringList.add(tree);//tree对象加入到list中
StringList.add(str);
stringList.add(tree)在编译的时候就提示错误,让使用者避免在运行时才能发现错误的尴尬。
问题来了,为什么会这么好用呢?
这是因为使用了泛型,泛型集合一旦声明了是合作数据类型的集合,就只能添加何种数据类型,而且泛型用不着类型的强制转换。所以,当你添加入不同类型,就会报错了。
3. 高效率
泛型集合一旦声明了是何种数据类型的集合,就只能添加何种数据类型。添加去也不会转换成Object(普通的集合添加,会强制把对象转换成object保存在集合中),它是运行时动态的获取类型参数。也就是说没有装箱和拆箱这些操作。减少了处理器的资源浪费。
三、 如何使用泛型
泛型有三种使用方式,分别为泛型类,泛型接口,泛型方法。
1. 泛型类,顾名思义就是用于类中的定义。
这是一个简单的泛型类的例子:
class Add<T>{
//id这个成员变量的类型为T,T的类型由外部指定
private Tid;
public Add(){
}//空构造函数
public Add(T id){// //泛型构造方法形参id的类型也为T,T的类型由外部指定
this.id= id;
}
public TgetId() {
returnid;
}
publicvoid setId(T id) {
this.id= id;
}
}
创建对象:
Add<Integer> addInteger = newAdd<Integer>();
那你猜一下,下面的代码可不可以通过编译?
Add add = new Add();
聪明的你一定已经知道了,答案是可以的。这是因为在使用泛型的时候如果传入泛型实参,则会根据传入的泛型实参做相应的限制,此时泛型才会起到本应起到的限制作用。
如果不传入泛型类型实参的话,在泛型类中使用泛型的方法或成员变量定义的类型可以为任何的类型。
泛型接口:
//定义一个泛型接口
interface Genericty<T> {
publicT update();
}
实现泛型接口的类:
/**
* 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
* 即:classAnimalGenericty <T> implements Genericty <T>{
* 如果不声明泛型,如:class AnimalGenericty implements Genericty <T>,编译器会报错:"Unknown class"
*/
class AnimalGenericty<T> implements Genericty<T>{
@Override
public T update () {
return null;
}
}
/**
* 传入泛型实参时:
* 在实现类实现泛型接口时,如果已经将泛型接口传入了实参类型,那么泛型接口里面所有使用了泛型的地方都要替换成传入的实参类型
*/
class AnimalGenericty implements Genericty <String>{
@Override
publicString update() {
//TODO Auto-generated method stub
returnnull;
}
}
泛型方法:
/*
方法控制方式(public)与返回值之间的<T>必不可少,同时这也声明了一个泛型T
*/
public <T > T getName (Add<T>id){//方法控制方式(public)和//返回类型之间的<T>必不可少
T test = id.getId();
return test;//返回值必须是泛型T
}
以上,就是简单的泛型介绍。 |