首页后端开发JAVA泛型的高级运用,代码重构必须要了解的技巧

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

时间2023-04-21 05:15:01发布访客分类JAVA浏览1468
导读:前言泛型相信大家都不陌生,经常都会用到,像在一些集合类啊,一些开源框架啊,这种东西随处可见,如果不能好好理解的话,看起源码来也会增加了一点儿复杂度。泛型的好处,扩展性强,低耦合业务内容,大幅度的减少重复代码。本篇文章,基于对泛型有一定了解,...

前言

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

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

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

泛型的运用

场景一

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

/**
 * @author: wangqp
 * @create: 2020-11-18 15:02
 */
public class GenericApplyT,U>
 {


    public T apply(T t){
    
        return t;

    }
    

    public ListString>
 getGenericClassName(){
    
        ListString>
     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 GenericApplyInteger,Boolean>
() {
}
    ;
    
        System.out.println(genericApply.getGenericClassName());

    }

}
    
1234567891011121314151617181920212223242526

运行结果:

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

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

场景二

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

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

接口类

public interface IGenericI>
 {
    
    void process(I i);

}
    
123

抽象类

public abstract class AbstractGenericT>
 {
    

    // 当前泛型真实类型的Class
    private final ClassT>
     modelClass;


    public AbstractGeneric(){
    
        ParameterizedType parameterizedType = (ParameterizedType)this.getClass().getGenericSuperclass();
    
        modelClass = (ClassT>
    )parameterizedType.getActualTypeArguments()[0];

    }
    

    public ClassT>
 getGeneric(){
    
        return modelClass;

    }

}
    
1234567891011121314

实现类

public class GenericImpl extends AbstractGenericString>
     implements IGenericBoolean>
{


    @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 IMultiParamInterfaceString,Integer>
{


    @Override
    public void process() {
    
        System.out.println("MultiParamsImpl is invoke process");

    }

    
    //测试
    public static void main(String[] args) {
    
        ClassMultiParamsImpl>
     multiParamsClass = MultiParamsImpl.class;
    
        //得到这个接口上的 所有泛型
        MapTypeVariable?>
    , Type>
     typeArguments = TypeUtils.getTypeArguments(multiParamsClass, IMultiParamInterface.class);
    
        for (Map.EntryTypeVariable?>
    , 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

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

运行结果:

总结

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

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!

javaJava编程程序员面试架构

若转载请注明出处: 泛型的高级运用,代码重构必须要了解的技巧
本文地址: https://pptw.com/jishu/4310.html
腾讯云服务器ip加白名单 腾讯云白名单配置 32天高效突击:框架+性能优化+微服务+分布式,笔记面试全有

游客 回复需填写必要信息