泛型的高级运用,代码重构必须要了解的技巧

342 篇文章 3 订阅
231 篇文章 0 订阅

前言

泛型相信大家都不陌生,经常都会用到,像在一些集合类啊,一些开源框架啊,这种东西随处可见,如果不能好好理解的话,看起源码来也会增加了一点儿复杂度。

泛型的好处,扩展性强,低耦合业务内容,大幅度的减少重复代码。

本篇文章,基于对泛型有一定了解,想更进一步运用的朋友。

泛型的运用

场景一

当我们写了一个采用泛型的类,但是怎么获取到这个类上的泛型呢,直接 run 一段简短的代码看下。

 
 

/** * @author: wangqp * @create: 2020-11-18 15:02 */ public class GenericApply<T,U> { public T apply(T t){ return t; } public List<String> getGenericClassName(){ List<String> ret = new ArrayList<>(); Type genericSuperclass = getClass().getGenericSuperclass(); Type[] actualTypeArguments = ((ParameterizedType) genericSuperclass).getActualTypeArguments(); Stream.of(actualTypeArguments).forEach(type -> { ret.add(((Class)type).getName()); }); return ret; } public static void main(String[] args) { // 匿名的子类实现 GenericApply genericApply = new GenericApply<Integer,Boolean>() {}; System.out.println(genericApply.getGenericClassName()); } } 1234567891011121314151617181920212223242526

运行结果:

编辑切换为居中

添加图片注释,不超过 140 字(可选)

可以看到,GenericApply 这类上有两个泛型参数,使用上面的方法后,咱们可以得到全面的泛型全类名。

注意: 类上加泛型,最好使用在抽象类上或者接口类上。

场景二

泛型在抽象类和接口类上,我们怎么运用获取呢,展示下代码。

这里划分了三个类,接口类、抽象类、实现类。

接口类

 
 

public interface IGeneric<I> { void process(I i); } 123

抽象类

 
 

public abstract class AbstractGeneric<T> { // 当前泛型真实类型的Class private final Class<T> modelClass; public AbstractGeneric(){ ParameterizedType parameterizedType = (ParameterizedType)this.getClass().getGenericSuperclass(); modelClass = (Class<T>)parameterizedType.getActualTypeArguments()[0]; } public Class<T> getGeneric(){ return modelClass; } } 1234567891011121314

实现类

 
 

public class GenericImpl extends AbstractGeneric<String> implements IGeneric<Boolean>{ @Override public void process(Boolean param) { } public static void main(String[] args) { GenericImpl generic = new GenericImpl(); System.out.println("抽象类上的泛型全类名 "+generic.getGeneric().getName()+"\n"); Type[] genericInterfaces = generic.getClass().getGenericInterfaces(); for (Type genericInterface : genericInterfaces) { Type[] actualTypeArguments = ((ParameterizedType) genericInterface).getActualTypeArguments(); Stream.of(actualTypeArguments).forEach(type -> { System.out.println("接口类上的泛型全类名 "+((Class) type).getName()); }); } } } 123456789101112131415161718192021

运行结果:

编辑切换为居中

添加图片注释,不超过 140 字(可选)

看到运行结果可以打印出抽象类上后者接口上的泛型,这种应该是咱们经常使用的方式。

场景三

还有种更高级的用法,这种用法是和注解一起用的。用于标记泛型。

咱们在上面可以看到泛型参数返回来的是个数组,也就是咱们必须知道这个类的泛型位置,才能找到数组上对应位置的泛型类。 有没有一种办法,我不通过数组下标呢。其实是有的,咱们可以通过注解的方式,标定我们的泛型类,不是很复杂,咱们可以一起来看下。直接简单看下代码。

注解类

 
 

//相当于标注,找到注解为 value 值的 泛型类 @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE_PARAMETER,ElementType.TYPE_USE}) public @interface MyAxis { String value() default ""; } 123456

接口泛型类

 
 

//相当于标注,找到注解为 value 值的 泛型类 public interface IMultiParamInterface<@MyAxis(FIRST) T extends String,@MyAxis(SECONDE) U extends Integer> { String FIRST="FIRST"; String SECONDE="SECONDE"; void process(); } 1234567

实现类

 
 

public class MultiParamsImpl implements IMultiParamInterface<String,Integer>{ @Override public void process() { System.out.println("MultiParamsImpl is invoke process"); } //测试 public static void main(String[] args) { Class<MultiParamsImpl> multiParamsClass = MultiParamsImpl.class; //得到这个接口上的 所有泛型 Map<TypeVariable<?>, Type> typeArguments = TypeUtils.getTypeArguments(multiParamsClass, IMultiParamInterface.class); for (Map.Entry<TypeVariable<?>, Type> typeVariableTypeEntry : typeArguments.entrySet()) { TypeVariable<?> key = typeVariableTypeEntry.getKey(); MyAxis annotation = AnnotationUtils.getAnnotation(key, MyAxis.class); Type value = typeVariableTypeEntry.getValue(); System.out.println("名称为:"+ annotation.value() +" 泛型类全限定名: "+value.getTypeName()); } } } 1234567891011121314151617181920

上面就是接口上有多个泛型,分别被标注为不同的名字,便于正确获取到想要的泛型类型。

运行结果:

编辑切换为居中

添加图片注释,不超过 140 字(可选)

总结

上面列举了泛型与抽象列,接口,注解在一起的多种运用和获取方式。泛型还是很重要的,希望我上面列举的对朋友们有点儿帮助。另外帮忙多点点赞呗,有什么疑问,大家可以评论区指出。

 资源获取:
大家 点赞、收藏、关注、评论啦 、 查看👇🏻👇🏻👇🏻 微信公众号获取联系方式👇🏻👇🏻👇🏻
精彩专栏推荐订阅:下方专栏👇🏻👇🏻👇🏻👇🏻

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值