Java中的泛型类,泛型方法,泛型接口
泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展
1.泛型类,是在实例化类的时候指明泛型的具体类型;支持创建可以按类型进行参数化的类(泛型类:实例化类的时候指明类的类型;public class Test<T>{};Test<Object> t = new Test<Object>();)
2.泛型方法,是在调用方法的时候指明泛型的具体类型。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样(泛型方法:调用的方法持有泛型;public <T>T getObj(Class<T> O){};可以把泛型看做参数/占位符)
3.泛型接口
泛型作用(不仅语言、类型系统和编译器有了较大的变化,以支持泛型,而且类库也进行了大翻修,所以许多重要的类,比如集合框架,都已经成为泛型化的):
1,(不用检查)类型安全。 泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。
2,消除强制类型转换。 所有的强制转换都是自动和隐式的。泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。
3,潜在的性能收益。 泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,程序员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来可能。由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改。所有工作都在编译器中完成,编译器生成类似于没有泛型(和强制类型转换)时所写的代码,只是更能确保类型安全而已。
泛型在使用中还有一些规则和限制:
1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
3、泛型的类型参数可以有多个。
4、泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上成为“有界类型”。
5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName(Java.lang.String);
泛型是什么意思在这就不多说了,而Java中泛型类的定义也比较简单,例如:public class Test<T>{}。这样就定义了一个泛型类Test,在实例化该类时,必须指明泛型T的具体类型,例如:Test<Object> t = new Test<Object>();,指明泛型T的类型为Object。
但是Java中的泛型方法就比较复杂了。
定义泛型方法语法格式如下:
调用泛型方法语法格式如下:
说明一下,定义泛型方法时,必须在返回值前边加一个<T>,来声明这是一个泛型方法,持有一个泛型T,然后才可以用泛型T作为方法的返回值。
Class<T>的作用就是指明泛型的具体类型,而Class<T>类型的变量c,可以用来创建泛型类的对象。
为什么要用变量c来创建对象呢?既然是泛型方法,就代表着我们不知道具体的类型是什么,也不知道构造方法如何,因此没有办法去new一个对象,但可以利用变量c的newInstance方法去创建对象,也就是利用反射创建对象。
泛型方法要求的参数是Class<T>类型,而Class.forName()方法的返回值也是Class<T>,因此可以用Class.forName()作为参数。其中,forName()方法中的参数是何种类型,返回的Class<T>就是何种类型。在本例中,forName()方法中传入的是User类的完整路径,因此返回的是Class<User>类型的对象,因此调用泛型方法时,变量c的类型就是Class<User>,因此泛型方法中的泛型T就被指明为User,因此变量obj的类型为User。
当然,泛型方法不是仅仅可以有一个参数Class<T>,可以根据需要添加其他参数。
为什么要使用泛型方法呢?因为泛型类要在实例化的时候就指明类型,如果想换一种类型,不得不重新new一次,可能不够灵活;而泛型方法可以在调用的时候指明类型,更加灵活。
public ResultDo<JxbkPasswordSetQueryBackPojo> invokePasswordSetQueryApi(JxbkPasswordSetQueryPojo jxbkPasswordSetQueryPojo) {
// 本地校验
ResultDo validDo = this.isAllFieldsValid(jxbkPasswordSetQueryPojo);
if (validDo.isError()) {
return validDo;
}
// 调用接口
Object resultObj = apiInvoke(jxbkPasswordSetQueryPojo, JxbkPasswordSetQueryBackPojo.class);
if (resultObj instanceof ResultDo) {
// 本地异常返回...
return (ResultDo) resultObj;
}
// 联机成功
JxbkPasswordSetQueryBackPojo jxbkPasswordSetQueryBackPojo = (JxbkPasswordSetQueryBackPojo) resultObj;
// 查询成功
ResultDo<JxbkPasswordSetQueryBackPojo> retDo = ResultDo.build();
retDo.setResult(jxbkPasswordSetQueryBackPojo);
return retDo;
}
工作中自己写的代码
private <T> Page<T> getList2Page(List<T> list, Pageable pageable) {
List<T> content = Lists.newArrayList();
int pageNum = pageable.getPageNumber();
int pageSize = pageable.getPageSize();
for (int i = pageNum * pageSize; i < (pageNum + 1) * pageSize; i++) {
if (i < list.size()) {
content.add(list.get(i));
}
}
Page<T> page = new PageImpl<T>(content, pageable, list.size());
return page;
}
private <T> List<T> getFtpList(Class<T> c, String[] result) throws Exception {
if (null == result) {
return new ArrayList<T>();
}
List<T> list = Lists.newArrayList();
for (int i = 0; i < result.length; i++) {
if (result[i].equals("null")) {
continue;
}
String[] resultSon = result[i].split("\\|");
T obj = c.newInstance();
Field[] fields = c.getDeclaredFields();
for (int j = 0; j < fields.length; j++) {
Field field = fields[j];
field.setAccessible(true);
String value = resultSon[j];
//获取 clazz 类型中的 propertyName 的属性描述器
PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(c, field.getName());
Method setMethod = pd.getWriteMethod();//从属性描述器中获取 set 方法
setMethod.invoke(obj, new Object[]{value});//调用 set 方法将传入的value值保存属性中去
}
list.add(obj);
}
return list;
}
private void copyPropertyByCustomAnno(Object target, Object src) {
try {
Field[] srcfields = src.getClass().getDeclaredFields();
for (int i = 0; i < srcfields.length; i++) {
Field field = srcfields[i];
if (field.isAnnotationPresent(ApiFieldAnnotation.class)) {
field.setAccessible(true);
String value = (field.get(src) == null || field.get(src).equals("")) ? "空(null)" : field.get(src).toString();
// DecimalFormat df = new DecimalFormat("###,###.##");
// if (field.getAnnotation(ApiFieldAnnotation.class).fieldClassType() == BigDecimal.class) {
// long money = Long.valueOf(value) / 100;
// value = df.format(money);
// }
//获取 clazz 类型中的 propertyName 的属性描述器
PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(target.getClass(), field.getName());
Method setMethod = pd.getWriteMethod();//从属性描述器中获取 set 方法
setMethod.invoke(target, new Object[]{value});//调用 set 方法将传入的value值保存属性中去
}
}
Field[] srcSupfields = src.getClass().getSuperclass().getDeclaredFields();
for (int j = 0; j < srcSupfields.length; j++) {
Field field = srcSupfields[j];
if (field.isAnnotationPresent(ApiFieldAnnotation.class)) {
field.setAccessible(true);
String value = field.get(src) == null ? "空(null)" : field.get(src).toString();
//获取 clazz 类型中的 propertyName 的属性描述器
PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(target.getClass(), field.getName());
Method setMethod = pd.getWriteMethod();//从属性描述器中获取 set 方法
setMethod.invoke(target, new Object[]{value});//调用 set 方法将传入的value值保存属性中去
}
}
} catch (Exception e) {
log.error("获取渤海银行字段失败。", e);
}
}
/**
* 解析银行存管Pojo
*/
private List<ReturnPojo> bhbkParseToReturnPojo(Object pojo) {
try {
List<ReturnPojo> params = Lists.newArrayList();
Field[] fields = pojo.getClass().getDeclaredFields();
Field[] fieldsSup = pojo.getClass().getSuperclass().getDeclaredFields();
Field[] fieldsAll = new Field[fields.length + fieldsSup.length];
for (int i = 0; i < fields.length; i++) {
fieldsAll[i] = fields[i];
}
for (int j = fields.length; j < fields.length + fieldsSup.length; j++) {
fieldsAll[j] = fieldsSup[j - fields.length];
}
params.addAll(bhbkParseToReturnPojo(fieldsAll, pojo));
return params;
} catch (Exception e) {
log.error("解析银行存管Pojo失败。", e);
return new ArrayList<ReturnPojo>();
}
}
private List<ReturnPojo> bhbkParseToReturnSonPojo(Object pojo) {
try {
List<ReturnPojo> params = Lists.newArrayList();
Field[] fields = pojo.getClass().getDeclaredFields();
params.addAll(bhbkParseToReturnPojo(fields, pojo));
return params;
} catch (Exception e) {
log.error("解析银行存管Pojo失败。", e);
return new ArrayList<ReturnPojo>();
}
}
private List<ReturnPojo> bhbkParseToReturnPojo(Field[] fields, Object pojo) {
try {
List<ReturnPojo> params = Lists.newArrayList();
for (Field field : fields) {
if (!field.isAnnotationPresent(ApiFieldAnnotation.class)
// || "sign".equals(field.getName())
) {
continue;
}
ApiFieldAnnotation annotation = field.getAnnotation(ApiFieldAnnotation.class);
field.setAccessible(true);
ReturnPojo returnPojo;
if (field.getAnnotation(ApiFieldAnnotation.class).fieldClassType() == BigDecimal.class) {
returnPojo = new ReturnPojo(field.getName(), annotation.fieldDesc() + "(元)", annotation.notNull(), field.get(pojo));
} else {
returnPojo = new ReturnPojo(field.getName(), annotation.fieldDesc(), annotation.notNull(), field.get(pojo));
}
params.add(returnPojo);
}
return params;
} catch (Exception e) {
log.error("解析银行存管Pojo失败。", e);
return new ArrayList<ReturnPojo>();
}
}
@Data
@AllArgsConstructor
private class ReturnPojo {
private String name;
private String nameZh;
private Boolean notNullFlag;
private Object defaultValue;
}
public class BhbkQueryChargeDetailBackPojo extends BhbkBasePojo {
@ApiFieldAnnotation(fieldClassType = String.class, fieldDesc = "大额充值账号", notNull = false, maxLength = 32)
private String chargeAccount;
@ApiFieldAnnotation(fieldClassType = String.class, fieldDesc = "大额充值账户户名", notNull = false, maxLength = 128)
private String accountName;
@ApiFieldAnnotation(fieldClassType = String.class, fieldDesc = "可用余额", notNull = false, maxLength = 16)
private String avlBal;
@ApiFieldAnnotation(fieldClassType = String.class, fieldDesc = "账户余额", notNull = false, maxLength = 16)
private String acctBal;
@ApiFieldAnnotation(fieldClassType = String.class, fieldDesc = "冻结余额", notNull = false, maxLength = 16)
private String frzBal;
}
ps:泛型能否代替object?
泛型的作用是为了参数的统一,Object不仅仅是这个功能,它是整个面向对象编程思维的基础,泛型是更好的开发方案!
泛型比object更好,体现在:泛型可以在编译期间检查类型错误,获得ide的上下文提示、无需运行时反射和转换,效率更高、编写的代码语义清晰更容易理解
上一篇: WebGL编程指南(1)简介
下一篇: 集合之浅谈HashSet