Java泛型方法和泛型参数之美

1.泛型方法和泛型参数的介绍

在这里插入图片描述

在Java中,泛型方法和泛型参数是一种强大的特性,它们可以增加代码的灵活性和可重用性。下面是对泛型方法和泛型参数的介绍:

  1. 泛型方法:
    泛型方法是一种在方法中使用泛型类型的方式。通过在方法声明中使用尖括号和类型参数,可以使方法具有通用性,可以在调用时指定具体的类型。泛型方法可以在返回类型之前使用类型参数,也可以在参数列表中使用类型参数。

    例如,下面是一个简单的泛型方法示例:

    public <T> void printArray(T[] array) {
        for (T element : array) {
            System.out.println(element);
        }
    }
    

    在上面的示例中,<T>表示类型参数,T[]表示接受一个泛型数组作为参数。在调用该方法时,可以传入任意类型的数组。

    上面的方法为没有返回结果的,也可以定义有返回结果的泛型参数,其中的返回参数的类型可以与传入的参数产生关系。

    在Java中,方法可以返回泛型类型。这样的方法可以在调用时指定具体的类型参数,从而实现灵活的类型处理。以下是一种常见的方法返回泛型的方式:

    public <T> T getGenericValue(T value) {
        // 在这里可以对value进行一些处理
        return value;
    }
    

    在上述代码中,<T>表示这是一个泛型方法,T是类型参数。方法的返回类型是T,即根据调用时传入的类型参数决定返回的具体类型。

    使用该方法时,可以根据需要传入不同的类型参数,例如:

    String stringValue = getGenericValue("Hello");
    Integer intValue = getGenericValue(123);
    

    在上述示例中,第一次调用getGenericValue方法时,传入的类型参数是String,所以返回值的类型是String;第二次调用时传入的类型参数是Integer,所以返回值的类型是Integer

    需要注意的是,泛型方法可以有多个类型参数,并且可以在方法参数、返回值、局部变量等位置使用这些类型参数。

  2. 泛型参数:
    泛型参数是一种在类、接口或方法中使用的类型参数。通过在类、接口或方法声明中使用尖括号和类型参数,可以使其具有通用性,可以在实例化或调用时指定具体的类型。

    例如,下面是一个简单的泛型类示例:

    public class Box<T> {
        private T item;
    
        public void setItem(T item) {
            this.item = item;
        }
    
        public T getItem() {
            return item;
        }
    }
    

    在上面的示例中,<T>表示类型参数,Box<T>表示一个泛型类。在实例化该类时,可以指定具体的类型,例如Box<Integer>Box<String>

2.实战应用

场景介绍:

这里想提供一个Util工具类的一个工具方法,用于获取任何对象的某个属性的值,先上改造后的代码:

优化后代码

说明:

这个方法里的内部逻辑还不够完善,请忽略这里面的内部取值逻辑缺陷,主要介绍泛型的使用。

import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

public class SyncUtil {
/**
     * 根据属性名称和类型获取对象对应的属性值
     * @param obj 需要获取属性的对象
     * @param propName 属性名
     * @param resultType 希望返回的类型
     * @return
     */
    public static <T> T getValueByPropertyName(Object obj, String propName, Class<T> resultType) {
        MetaObject meta = SystemMetaObject.forObject(obj);
        if (meta.hasGetter(propName)) {
            System.out.println(meta.getGetterType(propName).getName());
            if (meta.getValue(propName) instanceof Integer) {
                if (resultType.isAssignableFrom(Long.class)) {
                    return (T) Long.valueOf((Integer) meta.getValue(propName));
                }
            } else if (meta.getValue(propName) instanceof Long) {
                if (resultType.isAssignableFrom(Integer.class)) {
                    return (T) (Integer.valueOf(Math.toIntExact((Long) meta.getValue(propName))));
                }
            }
            if(resultType.isAssignableFrom(String.class)){
                if(meta.getValue(propName) == null ){
                    return null;
                }else{
                    return (T) meta.getValue(propName).toString();
                }
            }
        } else {
            throw new IllegalArgumentException(obj.getClass() + "中没有属性" + propName + "的get方法");
        }
        return (T)meta.getValue(propName);
    }
    
}

这里有三个参数,分别是obj 需要获取属性的对象,propName 属性名,resultType 希望返回的类型。

其中resultType定义的类型为 Class<T> ,这里需要返回的结果类型就是传入的入参类型的class。下面看看调用的地方:

SaveBudgetCloseCaseReq req = SaveBudgetCloseCaseReq.builder().applyId(emsApplyId)
    .orgId(getValueByPropertyName(head, "orgId", Long.class))
    .deptId(getValueByPropertyName(head, "deptId", Long.class))
    .deptName(getValueByPropertyName(head, "deptName", String.class))
    .personId(getValueByPropertyName(head, "personId", Long.class))
    .personName(getValueByPropertyName(head, "personName", String.class))
    .positionId(getValueByPropertyName(head, "positionId", Long.class))
    .positionName(getValueByPropertyName(head, "positionName", String.class))
    .sourceBillNo(getValueByPropertyName(head, "billNo", String.class))
    .sourceBillSystem(StoreRebateConstants.Ems2Code.EMS2_SOURCE_BILL_SYSTEM)
    .userId(getValueByPropertyName(head, "userId", Long.class))
    .closeCaseLines(lines).build();

从上面可以看出,获取后的结果就是需要返回的结果,不需要再做转换,可以省了很多事,而且代码看起来简介。

下面看看优化前的代码。

优化前代码

/**
     * 根据属性名称和类型获取对象对应的属性值
     * @param obj 需要获取属性的对象
     * @param propName 属性名
     * @param resultType 希望返回的类型
     * @return
     */
public static Object getValueByPropertyName(Object obj, String propName, Class<?> resultType) {
        MetaObject meta = SystemMetaObject.forObject(obj);
        if (meta.hasGetter(propName)) {
            System.out.println(meta.getGetterType(propName).getName());
            if (meta.getValue(propName) instanceof Integer) {
                if (resultType.isAssignableFrom(Long.class)) {
                    return Long.valueOf((Integer) meta.getValue(propName));
                }
            } else if (meta.getValue(propName) instanceof Long) {
                if (resultType.isAssignableFrom(Integer.class)) {
                    return Math.toIntExact((Long) meta.getValue(propName));
                }
            }
        } else {
            throw new IllegalArgumentException(obj.getClass() + "中没有属性" + propName + "的get方法");
        }
        return meta.getValue(propName);
    }

这里返回的类型为Object类型,获取的时候是需要去强转的,而在强转的时候可能出现异常,而且写起来很啰嗦,很繁琐。

下面看下调用的地方:

public static SaveBudgetCloseCaseReq buildEmsCloseCaseReq(Object head, List<SaveBudgetCloseCaseLineReq> lines) {
        SaveBudgetCloseCaseReq req = SaveBudgetCloseCaseReq.builder().closeCaseHeadId((Long) getValueByPropertyName(head, "closeCaseHeadId", Long.class))
                .orgId((Long) getValueByPropertyName(head, "orgId", Long.class))
                .deptId((Long) getValueByPropertyName(head, "deptId", Long.class))
                .deptName((String) getValueByPropertyName(head, "deptName", String.class))
                .personId((Long) getValueByPropertyName(head, "personId", Long.class))
                .personName((String) getValueByPropertyName(head, "personName", String.class))
                .positionId((Long) getValueByPropertyName(head, "positionId", Long.class))
                .positionName((String) getValueByPropertyName(head, "positionName", String.class))
                .sourceBillNo((String) getValueByPropertyName(head, "billNo", String.class))
                .sourceBillSystem(StoreRebateConstants.Ems2Code.EMS2_SOURCE_BILL_SYSTEM)
                .userId((Long) getValueByPropertyName(head, "userId", Long.class))
                .closeCaseLines(lines).build();
        req.setCloseCaseLines(lines);
        return req;
    }

可以看出,获取到结果后,都是做了强转的。

3.总结

使用泛型的好处:

1.提升了程序的健壮性和规范性

2.编译时,检查添加元素的类型,提高了安全性

3.减少了类型转换的次数,提高效率

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小灰灰-58

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值