超级通道: Java泛型学习系列-绪论
本章主要对Java泛型进行整体性介绍。
1.泛型简介
百度百科(修改版):
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做 显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况 ,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。 泛型的好处:使用泛型,首先可以通过IDE进行代码类型初步检查,然后在编译阶段进行编译类型检查,以保证类型转换的安全性;并且所有的强制转换都是自动和隐式的,可以提高代码的重用率。
2.泛型由来
泛型的思想早就存在,在C++中的类模板(Template)就是用到了泛型的思想。 在JDK1.5之前,可以通过继承实现这种泛型思想。 查看ArrayList(JDK1.5)之前的定义如下:
public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
private transient Object[] elementData;
private int size;
//...
public boolean add(Object paramObject)
{
ensureCapacity(this.size + 1);
this.elementData[(this.size++)] = paramObject;
return true;
}
//...
public Object get(int paramInt)
{
RangeCheck(paramInt);
return this.elementData[paramInt];
}
}
可以看到,ArrayList的本质是一个Object数组Object[] elementData。 这种做法虽然实现了泛型思想,但是有以下问题:
ArrayList实例化之后,可以随意添加任意类型的对象(Obeject是任意引用类型的基类)。获取元素的前提是:需要提前知道列表元素的类型。获取列表元素时,都需要进行显式类型转换。容易发生类型转换出错的问题。
如下面的代码:
//JDK1.5之前的ArrayList的用法
ArrayList arrayList = new ArrayList();
//可以随意添加任意类型的对象
arrayList.add(1);//Integer
arrayList.add("1");//String
//张三前辈知道第一个元素是Integer类型的,所以他写的程序没错
Integer integer = (Integer) arrayList.get(0);
LOGGER.info("张三前辈取值:" + integer);
//李四不知道第二个元素是什么类型,因为张三前辈已经离职了,但他看张三前辈使用Integer取值的,
// 所以他猜测也是Integer类型的,但是他没想到实际是String类型的,所以会报类型转换错误
Integer integer1 = (Integer)arrayList.get(1);
LOGGER.info("李四后生取值:" + integer1);
代码执行结果:
INFO - 张三前辈取值:1
2018-02-12 16:56:57 INFO BeforJDK5:26 - 张三前辈取值:1
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at pers.hanchao.generics.before.BeforJDK5.main(BeforJDK5.java:29)
为了解决上面的问题,JDK1.5加入了泛型。加入泛型是为了解决类型转换的安全隐患,具体体现如下:
解决泛型对象实例化之后,可以随意添加任何类型的对象的问题。解决获取泛型元素前,需要提前确定元素的类型的问题。解决获取元素时,需要进行显式类型转换的问题。解决容易出现类型转换出错的问题。
使用泛型的解决方式:
//JKD1.5之后的ArrayList
ArrayList<Integer> integerArrayList = new ArrayList<Integer>();
integerArrayList.add(1);//添加Integer正常
//不能添加String类型,因为无法通过IDE的初步类型检查
//integerArrayList.add("1");
//王五不需要问前辈,就很容易知道这个列表存储的是Integer
Integer integer2 = integerArrayList.get(0);
LOGGER.info("王五后生取值:" + integer2);
运行结果
2018-02-12 16:56:37 INFO BeforJDK5:39 - 王五后生取值:1
3.入门示例
泛型可以应用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。下面对这三种使用方式提供简单的入门示例:
package pers.hanchao.generics.hello;
import org.apache.log4j.Logger;
/**
* 泛型类示例
* Created by 韩超 on 2018/2/12.
*/
public class HelloWorld<T> {
private final static Logger LOGGER = Logger.getLogger(HelloWorld.class);
private T t;
public T getValue() {
return t;
}
public void setValue(T t) {
this.t = t;
}
public static void main(String[] args){
LOGGER.info("泛型类示例:");
//泛型类示例
HelloWorld<String > helloWorld = new HelloWorld<String >();
helloWorld.setValue("Hello World!");
//IDE提供的类型检查确保只能设置String类型的对象,Long类型报错
//helloWorld.setValue(5211314L);
LOGGER.info(helloWorld.getValue());
HelloWorld<Long> helloWorld1 = new HelloWorld<Long>();
helloWorld1.setValue(5211314L);
//IDE提供的类型检查确保只能设置Long类型的对象,String类型报错
//helloWorld1.setValue("Hello World!");
LOGGER.info(helloWorld1.getValue() + "\n");
LOGGER.info("泛型方法示例:");
//泛型方法示例
printHelloWorld("Hello World!");
printHelloWorld(5211314 + "\n");
LOGGER.info("泛型接口示例");
//泛型接口示例
MyInterface myHelloWorld = new MyHelloWorld();
//Number类型都可以
myHelloWorld.print(5211314L);
myHelloWorld.print(521);
//String类型不可以
//myHelloWorld.print("S");
}
/**
* <p>Title: 泛型方法</p>
* @author 韩超 2018/2/12 17:14
*/
static <T> void printHelloWorld(T t){
LOGGER.info(t);
}
/**
* <p>Title: 泛型接口</p>
* @author 韩超 2018/2/12 17:15
*/
interface MyInterface<T extends Number>{
void print(T t);
}
static class MyHelloWorld implements MyInterface{
@Override
public void print(Number number) {
LOGGER.info(number);
}
}
}
运行结果:
2018-02-12 17:22:15 INFO HelloWorld:23 - 泛型类示例:
2018-02-12 17:22:15 INFO HelloWorld:27 - Hello World!
2018-02-12 17:22:15 INFO HelloWorld:31 - 5211314
2018-02-12 17:22:15 INFO HelloWorld:33 - 泛型方法示例:
2018-02-12 17:22:15 INFO HelloWorld:53 - Hello World!
2018-02-12 17:22:15 INFO HelloWorld:53 - 5211314
2018-02-12 17:22:15 INFO HelloWorld:38 - 泛型接口示例
2018-02-12 17:22:15 INFO HelloWorld:67 - 5211314
2018-02-12 17:22:15 INFO HelloWorld:67 - 521
4.其他说明
泛型是向前兼容的:JDK1.5之前未使用泛型类可以不加修改的继续工作,但是却无法享受泛型的好处的。泛型的设计初衷:是为了减少类型转换错误产生的安全隐患,而不是为了实现任意化,一定要记住这个初衷。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。