Java泛型(包括泛型+反射的应用)

阅读: 评论:0

Java泛型(包括泛型+反射的应用)

Java泛型(包括泛型+反射的应用)

泛型简介

Java 泛型(generics)是 JDK 5 中引入的一个新特性,泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。

泛型的本质是参数化类型,也就是说,所操作的数据类型被指定为一个参数。在创建对象或调用方法的时候才明确具体的类型。

类型擦除

正确理解泛型概念的首要前提是理解类型擦除

更多关于类型擦除的问题,可以查看这篇文章:《Java泛型类型擦除以及类型擦除带来的问题》

什么是类型擦除

Java的泛型是伪泛型,这是因为Java在编译期间,所有的泛型信息都会被擦除。Java的泛型基本上都是在编译器这个层次上实现的,在生成的字节码中是不包含泛型中的类型信息的。

  • 使用泛型的时候加上类型参数,在编译器编译的时候参数会被去掉,这个过程称为类型擦除

如在代码中定义List<String>等类型,在编译后都会变成List,由泛型附加的类型信息对JVM是看不到的JVM看到的只是List。Java编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法在运行时刻出现的类型转换异常的情况,类型擦除也是Java的泛型与C++模板机制实现方式之间的重要区别。

通配符

更多关于Java 泛型中的通配符可以查看这篇文章:《聊一聊-JAVA 泛型中的通配符 T,E,K,V,?》

常用的通配符为: T、E、K、V、?

  • ? 表示不确定的 Java 类型
  • T 表示具体的一个Java类型(Type)
  • KV 分别代表 Java 键值中的 Key Value
  • E 代表Element

泛型的三种使用方式

泛型一般有三种使用方式:泛型类泛型接口泛型方法

泛型类

此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。

在实例化泛型类时,必须指定T的具体类型。

public class Generic<T>{ private T key;public Generic(T key) { this.key = key;}public T getKey(){ return key;}
}

实例化泛型类:

Generic<Integer> genericInteger = new Generic<Integer>(123456);

泛型接口

public interface Generator<T> {public T method();
}
  1. 实现泛型接口,不指定类型:
class GeneratorImpl<T> implements Generator<T>{@Overridepublic T method() {return null;}
}
  1. 实现泛型接口,指定类型:
class GeneratorImpl<T> implements Generator<String>{@Overridepublic String method() {return "hello";}
}

泛型方法

public static <E> void printArray(E[] inputArray){         for(E element : inputArray){        System.out.printf( "%s ", element );}System.out.println();
}

使用:

// 创建不同类型数组: Integer, Double 和 Character
Integer[] intArray = { 1, 2, 3 };
String[] stringArray = { "Hello", "World" };
printArray(intArray); 
printArray(stringArray); 

泛型的优点

使用泛型的好处就是:

  1. 代码更加简洁,不再需要强制类型转换

  2. 程序更加健壮,在编译期间没有警告,在运行期就不会出现ClassCastException异常

  3. 提高代码的复用性,比如:在动态代理中,通过泛型可以代理任何需要被代理的类

public class ServiceProxy<T> implements InvocationHandler {private T target;public ServiceProxy(T target) {this.target = target;}
}

泛型的应用

  1. 操作集合时

容器中之所以可以存储各种类型的对象,就是因为引入了泛型

List lists = new ArrayList<String>();
  1. 用于基础组件时

因为组件的要求是需要做到一定的通用性,需要支持不同的类型,而泛型的特点是:在创建对象或调用方法的时候才明确具体的类型。可以参考SpringData JPAJpaRepository的写法:

public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryExampleExecutor<T> {List<T> findAll();List<T> findAll(Sort sort);List<T> findAllById(Iterable<ID> ids);<S extends T> List<S> saveAll(Iterable<S> entities);void flush();<S extends T> S saveAndFlush(S entity);void deleteInBatch(Iterable<T> entities);void deleteAllInBatch();T getOne(ID id);@Override<S extends T> List<S> findAll(Example<S> example);@Override<S extends T> List<S> findAll(Example<S> example, Sort sort);
}

此外,在组件中,还离不开Java的反射机制,一般是反射+泛型

再举个实际的例子

比如有个需求是将某些数据库表的某些字段进行聚合,SQL语句就是

select sum(column1),sum(column2) from table group by field1,field2

需要sumgroup by 的列是由业务方自己传入,而SQL表其实就是我们的POJO,传入的字段肯定也是POJO的属性,单个业务实际可以在参数上将POJO写死,但是如果参数设置为泛型,便可以提高代码的复用性。

拿到参数后,通过反射获取其字段具体的值,就可以做累加了。具体代码示例如下:

// 传入需要 group by 和 sum 的字段名
public cacheMap(List<String> groupByKeys, List<String> sumValues) {upByKeys = groupByKeys;this.sumValues = sumValues;
}private void excute(T e) {// 从pojo 取出需要group by 的字段 listList<Object> key = buildPrimaryKey(e);// primaryMap 是存储结果的MapT value = (key);// 如果从存储结果找到有相应记录if (value != null) {for (String elem : sumValues) {// 反射获取对应的字段,做累加处理Field field = getDeclaredField(elem, e);if ((e) instanceof Integer) {field.set(value, (Integer) (e) + (Integer) (value));} else if ((e) instanceof Long) {field.set(value, (Long) (e) + (Long) (value));} else {throw new RuntimeException("类型异常,请处理异常");}}// 处理时间记录Field field = getDeclaredField("updated", value);if (null != field) {field.set(value, CurrentTime());}} else {// group by 字段 第一次进来try {primaryMap.put(key, Tclone(e));createdMap.put(key, CurrentTime());}catch (Exception ex) {log.info("first put value error {}" , e);}}
}

参考:

本文发布于:2024-01-28 07:35:13,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/17063985195828.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:反射   Java   泛型
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23