前言
泛型相信大家都不陌生,经常都会用到,像在一些集合类啊,一些开源框架啊,这种东西随处可见,如果不能好好理解的话,看起源码来也会增加了一点儿复杂度。
泛型的好处,扩展性强,低耦合业务内容,大幅度的减少重复代码。
本篇文章,基于对泛型有一定了解,想更进一步运用的朋友。
泛型的运用
场景一
当我们写了一个采用泛型的类,但是怎么获取到这个类上的泛型呢,直接 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
运行结果:
泛型的高级运用,代码重构必须要了解的技巧可以看到,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
运行结果:
泛型的高级运用,代码重构必须要了解的技巧看到运行结果可以打印出抽象类上后者接口上的泛型,这种应该是咱们经常使用的方式。
场景三
还有种更高级的用法,这种用法是和注解一起用的。用于标记泛型。
咱们在上面可以看到泛型参数返回来的是个数组,也就是咱们必须知道这个类的泛型位置,才能找到数组上对应位置的泛型类。
有没有一种办法,我不通过数组下标呢。其实是有的,咱们可以通过注解的方式,标定我们的泛型类,不是很复杂,咱们可以一起来看下。直接简单看下代码。
注解类
//相当于标注,找到注解为 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
上面就是接口上有多个泛型,分别被标注为不同的名字,便于正确获取到想要的泛型类型。
运行结果:
泛型的高级运用,代码重构必须要了解的技巧总结
上面列举了泛型与抽象列,接口,注解在一起的多种运用和获取方式。泛型还是很重要的,希望我上面列举的对朋友们有点儿帮助。另外帮忙多点点赞呗,有什么疑问,大家可以评论区指出。
作者:vicoqi
网友评论