本文主要讲解道java泛型类,泛型方法的应用实例, 从这里可以下载到完整的java代码工程: http://download.csdn.net/detail/hejiangtao/3996520
近短时间需要使用泛型,就研究了下,发现网上的问关于泛型的文章都是讲原理的, 很少有提到那里用泛型比较合适, 本文就泛型类和泛型方法的使用给出两 个典型应用场景. 例如一个toString的泛型方法,就可以将所有的Bean按照指定格式转换成字符串, 就可以避免每个Bean都要实现toString方法.
1. 先简单说两句我对泛型的理解
泛型的本质就是将数据类型也参数化, 普通方法的输入参数的值是可以变的,但是类型(比如: String)是不能变的,它使得了在面对不同类型的输入参数的时候我们要重载方法才行. 泛型就是将这个数据类型也搞成跟参数的值一样可以变的.
泛型分为泛型接口,泛型类和泛型方法. 泛型接口,泛型类大家都比较熟悉了,应该都用过List, ArrayList. List就是泛型接口,ArrayList就是泛型类,我们经常看到List
的声明, new ArrayList ()的定义, 这里面的E可以是String, 也可以自己定义的类(例如: CarBean). 我感觉泛型类就JDK提供的就基本够用了,自定义使用的场景非常少了. 反而是泛型方法,对与解析自定义数据结构非常有用, 类似于toString这种场景是百试不爽. java泛型的性能应该是没有问题的,说白了就是JDK做了个类型转换呗,很多网友就验证过, 我懒得验了,感兴趣的可以参考下我转载的这篇文章: http://blog.csdn.net/hejiangtao/article/details/7173838
2. 泛型类应用实例(泛型接口不再举例,跟类差不多)
3. 泛型方法应用实例我理解泛型类就是简化版的extend 或者overwrite, 例如ArrayList, 如果对象需要add, getIndex等数组操作就可以生成一个该对象的ArrayList, 使用扩展或者重写可以实现,但是明显泛型要简便的多,定义个新对象就搞定了.
泛型类实例就是延续这个思路, 车和房子都有品牌,名字和价钱,都是商品或者货物这种数据结构,一般需要获取品牌,名字和价钱的描述信息. 我就将货物定义为泛型类,获取描述信息就是泛型类里面的通用方法.
房和车的Bean先贴出来,一看就明白,不赘述了.
HouseBean.java
/** * Author: Jiangtao He; Email: [email protected] * Date: 2012-1-3 * Since: MyJavaExpert v1.0 * Description: */ public class HouseBean { private String brand; private String name; private String price; //省略了set/get方法 }
CarBean.java
package com.ross.generic.bean; /** * Author: Jiangtao He; Email: [email protected] * Date: 2012-1-3 * Since: MyJavaExpert v1.0 * Description: Store Car's information */ public class CarBean { private String brand; private String name; private String price; //省略了set/get方法 }
Goods的泛型类也定义出来,就是类名后面加个
, 他的主要功能就是获取泛型实例化的类型,并返回描述信息. setData方法就是将实例化对象的信息设置下, 然后在泛型类的方法中进行规整(当然实际应用的时候是可以先做查询数据库等分析,然后给出完整描述,例如售后服务,品牌推广等信息); getClassType方法就是范围实例化对象的类型了, 主要是方便体验. 下面是代码:
GenericGoods.java
package com.ross.generic; import java.lang.reflect.Method; /** * Author: Jiangtao He; Email: [email protected] * Date: 2012-1-3 * Since: MyJavaExpert v1.0 * Description: sample of generic class */ public class GenericGoods
{ private T t; private String information; /** * Description: default constructor. To get an object of the generic class */ public GenericGoods(T oT) { this.t = oT; } /** * @param sBrand: brand of the goods * @param sName: name of the goods * @param sPrice: price of the goods * Description: set the data for the object */ public void setData(String sBrand, String sName, String sPrice) { this.information = "This " + sName + " of " + sBrand + " costs " + sPrice + "!"; } public String getClassType() { return t.getClass().getName(); } //省略了set/get方法 }
我们写个Main函数运行 一下.
控制台打印信息:package com.ross.generic; import java.lang.reflect.InvocationTargetException; import com.ross.generic.bean.CarBean; import com.ross.generic.bean.HouseBean; /** * Author: Jiangtao He; Email: [email protected] * Date: 2012-1-4 * Since: MyJavaExpert v1.0 * Description:test the generic class and method */ public class MyMain { public static void main(String[] args) throws SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { // Car bean generic class test GenericGoods
oGGCar = new GenericGoods (new CarBean()); oGGCar.setData("Mercedes", "Benz", "666,000 RMB"); System.out.println("CarBean test: Type of class - " + oGGCar.getClassType() + "; Information of the goods: " + oGGCar.getInformation()); // House bean generic class test GenericGoods oGGHouse = new GenericGoods ( new HouseBean()); oGGHouse.setData("Shenzhen Wanke City", "3 rooms with 3 restrooms house", "2,000,000 RMB"); System.out.println("HouseBean test: Type of class - " + oGGHouse.getClassType() + "; Information of the goods: " + oGGHouse.getInformation()); } } CarBean test: Type of class - com.ross.generic.bean.CarBean; Information of the goods: This Benz of Mercedes costs 666,000 RMB! HouseBean test: Type of class - com.ross.generic.bean.HouseBean; Information of the goods: This 3 rooms with 3 restrooms house of Shenzhen Wanke City costs 2,000,000 RMB!
同样的基于上面的房和车的Bean进行功能验证-:)
概念不要弄混了, 泛型方法不一定要在泛型类里面. 这个GenericMethodProcess类不是泛型类, 在其中定义了定义了我们泛型方法toString, 它的功能就是按照指定的格式将Bean转换成String (当然,这种场景我们可以实现其他的功能,比如将表数据读取到Bean中,一个泛型方法可以搞定所有表). 代码中有详细注释不在解释了,其中用到了一点反射机制,不熟悉的可以网上搜点资料了解,或关注我后续博客.
GenericMethodProcess.java
我们写个Main函数运行 一下.package com.ross.generic; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * Author: Jiangtao He; Email: [email protected] * Date: 2012-1-3 * Since: MyJavaExpert v1.0 * Description:sample of generic method */ public class GenericMethodProcess { /** * Author: Jiangtao He; Email: [email protected] * Date: 2012-1-3 * Description: * 1. this method will convert bean to string in this format: * field_name_1=field_value_1;field_name_12=field_value_2;field_name_3=field_value_3... * 2. The field of the bean can only be basic java data type like 'int' or object type like 'String'; * If you want support self-define class type like "com.ross.generic.CarBean", you need extend the method -:) * @throws NoSuchMethodException * @throws SecurityException * @throws InvocationTargetException * @throws IllegalAccessException * @throws IllegalArgumentException */ public
String toString(T oT) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { // define return value String sRet = ""; // temporary variables String sGetMethodName = ""; String sFieldName = ""; Method oMethod; Field[] oFields = oT.getClass().getDeclaredFields(); if (null != oFields) { for (int i = 0; i < oFields.length; i++) { // to access the private field oFields[i].setAccessible(true); // get field name sFieldName = oFields[i].getName(); // get method name if (sFieldName.length() > 1) { sGetMethodName = "get" + sFieldName.substring(0, 1).toUpperCase() + sFieldName.substring(1, sFieldName.length()); } else { sGetMethodName = "get" + sFieldName.toUpperCase(); } // get set method oMethod = oT.getClass().getMethod(sGetMethodName); // get value sRet = sRet + sFieldName + "=" + oMethod.invoke(oT) + ";"; } } // remove the last separator: ';' if (!"".equals(sRet)) { sRet = sRet.substring(0, sRet.length() - 1); } return sRet; } }
控制台打印信息:package com.ross.generic; import java.lang.reflect.InvocationTargetException; import com.ross.generic.bean.CarBean; import com.ross.generic.bean.HouseBean; /** * Author: Jiangtao He; Email: [email protected] * Date: 2012-1-4 * Since: MyJavaExpert v1.0 * Description:test the generic class and method */ public class MyMain { public static void main(String[] args) throws SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { // define a object for generic method test GenericMethodProcess oGMP = new GenericMethodProcess(); // Car bean generic method test CarBean oCarBean = new CarBean(); oCarBean.setBrand("Mercedes"); oCarBean.setName("BMW"); oCarBean.setPrice("888,000 RMB"); String sBeanStr = oGMP.toString(oCarBean); System.out.println("CarBean toString: " + sBeanStr); // House bean generic method test HouseBean oHouseBean = new HouseBean(); oHouseBean.setBrand("Shanghai Wanke City"); oHouseBean.setName("4 rooms with 4 restrooms house"); oHouseBean.setPrice("6,000,000 RMB"); sBeanStr = oGMP.toString(oHouseBean); System.out.println("HouseBean toString: " + sBeanStr); } }
CarBean toString: brand=Mercedes;name=BMW;price=888,000 RMB HouseBean toString: brand=Shanghai Wanke City;name=4 rooms with 4 restrooms house;price=6,000,000 RMB
4.泛型的一些规则和限制
1) 泛型的类型参数只能是类类型(包括自定义类),不能是基本数据类型。
2) 泛型的类型参数可以有多个。
3) 泛型的参数类型可以使用extends语句,例如
。习惯上称为“有界类型”。 4) 泛型的参数类型还可以是通配符类型。例如Class> classType = Class.forName("java.lang.String");
注: 转载请注明出处: http://hejiangtao.iteye.com/, 用于商业得给我分成