之前在参与公司RPC框架开发过程中,使用java泛型编写了RPC客户端模块的相关代码。由于泛型代码相关知识应用程序员除了在使用相关集合时有用到外,其他地方很少用到,今天是2016年元旦刚好有时间总结一下java泛型的相关知识,顺便做一下笔记方便自己回顾,也便于和大家交流学习。
(一):为什么要用泛型?
很多人会问泛型从语法层面上讲感觉很复杂,尤其是边界通配符泛型语法非常抽象,为什么要用泛型呢?
因为泛型语法相比使用Object对象实现的“泛型”可以使程序具有更好的可读性和安全性
其实泛型属于java的一种语法糖,使用泛型可以大大降低程序的复杂性提高程序的健壮性。
在java引入泛型类型之前,泛型程序设计是使用继承实现的,
/**使用这种方式会带来两个问题
* java 1.5添加泛型机制之前 java的泛型是通过Object进行转换的
* @author Administrator
*
*/
public class ArrayList_Object {
private Object[] elementData;
//...
public Object get(int i){
//...
}
public void add(Object o){
//...
}
}
(1) 添加值没有类型检查,可以向数据中添加任何值
ArrayList_Object list = new ArrayList_Object();
list.add(new String("hello"));
(2)获取值时需要进行强制类型转换
String value = (String)list.get(0);
而java 1.5所添加的泛型机制提供了“类型参数”机制来指示元素的类型。
我们知道 在定义一个如下的普通函数时 我们会为函数提供形式参数int a和int b,这里参数a和b的名字是可以变化的,但是参数类型必须明确。
public void Method(int a, String b){
//...
}
而泛型的参数类型是可以不明确的,这种机制就是“类型参数”机制。
(二)泛型类和泛型方法的定义
/**Result 类引入了一个类型变量T,用尖括号<> 括起来,并放在类的后面,当然如果类中的成员域如果是多个类型,我们也可以引入多个类型变量如:
* 定义一个通用的处理返回结果的泛型类
* @author Administrator
*
* @param <T>
*/
public class Result<T> {
private T code;
private T message;
public Result(T code, T message){
this.code = code;
this.message = message;
}
public T getCode() {
return code;
}
public void setCode(T code) {
this.code = code;
}
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
}
public class Result<T,U> {
private T code;
private U message;
}
泛型类的使用方法示例如下所示:
public class GenericClassLearn {
public static void main(String[] args) {
// TODO Auto-generated method stub
GenericClassLearn gc = new GenericClassLearn();
Result<String> result = gc.getResult();
System.out.println("code: "+ result.getCode() + " "+ " message: "+ result.getMessage() );
}
/**
* 定义一个方法 结果返回泛型类的对象
* @return
*/
public static Result<String> getResult(){
//do something else
return new Result<String>("1","success");
}
}
输出结果:
code: 1 message: success
除了定义泛型类之外,我们还可以定义一种带有类型参数的简单方法,这种方法既可以定义在泛型类中,又可以定义在普通类中。
/**输出结果:
* 泛型方法示例
* @author Administrator
*
*/
public class GenericMethod {
public <T> Result<T> getResult(T ... t){
System.out.println(t.length);
return new Result<T>(t[0],t[1]);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
GenericMethod gm = new GenericMethod();
Result<String> result = gm.getResult("code:1","message:success");
System.out.println("code: "+ result.getCode() + " "+ " message: "+ result.getMessage() );
}
}
2
code: code:1 message: message:success
我们在普通类GenericMethod中定义了一个泛型方法getResult(T... t) ,注意类型变量<T>放在修饰符public之后,返回值Result<T>之前。
(3)类型变量的限定
我们在上例泛型方法中public <T> Result<T> getResult(T ... t)中,调用了t.length可变长参数t的length成员域,如果我们要处理某一个类族中的一个特定方法,那么
如何保证所传入的参数有这个方法呢?解决方法就是对类型参数加以约束。
我们在基类Apple中定义了一个getAppleColor()方法,然后定义子类GreenApple,并且在子类中定义了一个泛型方法
public static <T extends Apple> void getAppleColor(T apple)我们希望在泛型方法中得到任何apple的颜色,这里为了保证任何apple具有getAppleColor()方法,我们对类型参数进行了约束<T extends Apple>,使用了java中已经存在的关键字extends来进行约束。
/**
* 定义包含getAppleColor()方法的基类Apple
* @author Administrator
*
*/
public class Apple {
private String appleColor;
public String getAppleColor(){
return appleColor;
}
}
/**
* GreenApple类继承Apple
* @author Administrator
*
*/
public class GreenApple extends Apple{
private String appleColor;
public GreenApple(String appleColor){
this.appleColor = appleColor;
}
public String getAppleColor(){
return appleColor;
}
/**
* 泛型方法中的类型参数限定为基类为Apple的类
* @param apple
*/
public static <T extends Apple> void getAppleColor(T apple){
//只有Apple的子类才具有getAppleColor()这个方法
String appleColor = apple.getAppleColor();
System.out.println("appleColor : " + appleColor);
}
public static void main(String [] args){
GreenApple.getAppleColor(new GreenApple("green"));
}
}
输出结果:
appleColor : green