欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java中的泛型类,泛型方法,泛型接口

程序员文章站 2022-05-23 14:18:36
...

泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展

1.泛型类,是在实例化类的时候指明泛型的具体类型;支持创建可以按类型进行参数化的类(泛型类:实例化类的时候指明类的类型;public class Test<T>{};Test<Object> t = new Test<Object>();)

2.泛型方法,是在调用方法的时候指明泛型的具体类型。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样(泛型方法:调用的方法持有泛型;public <T>T getObj(Class<T> O){};可以把泛型看做参数/占位符)

3.泛型接口

泛型作用(不仅语言、类型系统和编译器有了较大的变化,以支持泛型,而且类库也进行了大翻修,所以许多重要的类,比如集合框架,都已经成为泛型化的):
1,(不用检查)类型安全。 泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。

2,消除强制类型转换 所有的强制转换都是自动和隐式的。泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。

3,潜在的性能收益。 泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,程序员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来可能。由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改。所有工作都在编译器中完成,编译器生成类似于没有泛型(和强制类型转换)时所写的代码,只是更能确保类型安全而已。

泛型在使用中还有一些规则和限制:
    1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
    2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
    3、泛型的类型参数可以有多个。
    4、泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上成为“有界类型”。
    5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName(Java.lang.String);

 泛型是什么意思在这就不多说了,而Java中泛型类的定义也比较简单,例如:public class Test<T>{}。这样就定义了一个泛型类Test,在实例化该类时,必须指明泛型T的具体类型,例如:Test<Object> t = new Test<Object>();,指明泛型T的类型为Object。

       但是Java中的泛型方法就比较复杂了。

       定义泛型方法语法格式如下:

Java中的泛型类,泛型方法,泛型接口


调用泛型方法语法格式如下:

Java中的泛型类,泛型方法,泛型接口


说明一下,定义泛型方法时,必须在返回值前边加一个<T>,来声明这是一个泛型方法,持有一个泛型T,然后才可以用泛型T作为方法的返回值。

       Class<T>的作用就是指明泛型的具体类型,而Class<T>类型的变量c,可以用来创建泛型类的对象。

       为什么要用变量c来创建对象呢?既然是泛型方法,就代表着我们不知道具体的类型是什么,也不知道构造方法如何,因此没有办法去new一个对象,但可以利用变量c的newInstance方法去创建对象,也就是利用反射创建对象。

       泛型方法要求的参数是Class<T>类型,而Class.forName()方法的返回值也是Class<T>,因此可以用Class.forName()作为参数。其中,forName()方法中的参数是何种类型,返回的Class<T>就是何种类型。在本例中,forName()方法中传入的是User类的完整路径,因此返回的是Class<User>类型的对象,因此调用泛型方法时,变量c的类型就是Class<User>,因此泛型方法中的泛型T就被指明为User,因此变量obj的类型为User。

       当然,泛型方法不是仅仅可以有一个参数Class<T>,可以根据需要添加其他参数。

       为什么要使用泛型方法呢?因为泛型类要在实例化的时候就指明类型,如果想换一种类型,不得不重新new一次,可能不够灵活;而泛型方法可以在调用的时候指明类型,更加灵活。

 

public ResultDo<JxbkPasswordSetQueryBackPojo> invokePasswordSetQueryApi(JxbkPasswordSetQueryPojo jxbkPasswordSetQueryPojo) {
        // 本地校验
        ResultDo validDo = this.isAllFieldsValid(jxbkPasswordSetQueryPojo);
        if (validDo.isError()) {
            return validDo;
        }
        // 调用接口
        Object resultObj = apiInvoke(jxbkPasswordSetQueryPojo, JxbkPasswordSetQueryBackPojo.class);
        if (resultObj instanceof ResultDo) {
            // 本地异常返回...
            return (ResultDo) resultObj;
        }
        // 联机成功
        JxbkPasswordSetQueryBackPojo jxbkPasswordSetQueryBackPojo = (JxbkPasswordSetQueryBackPojo) resultObj;
        // 查询成功
        ResultDo<JxbkPasswordSetQueryBackPojo> retDo = ResultDo.build();
        retDo.setResult(jxbkPasswordSetQueryBackPojo);
        return retDo;

    }

工作中自己写的代码

private <T> Page<T> getList2Page(List<T> list, Pageable pageable) {
        List<T> content = Lists.newArrayList();
        int pageNum = pageable.getPageNumber();
        int pageSize = pageable.getPageSize();
        for (int i = pageNum * pageSize; i < (pageNum + 1) * pageSize; i++) {
            if (i < list.size()) {
                content.add(list.get(i));
            }
        }
        Page<T> page = new PageImpl<T>(content, pageable, list.size());
        return page;
    }

    private <T> List<T> getFtpList(Class<T> c, String[] result) throws Exception {
        if (null == result) {
            return new ArrayList<T>();
        }
        List<T> list = Lists.newArrayList();
        for (int i = 0; i < result.length; i++) {
            if (result[i].equals("null")) {
                continue;
            }
            String[] resultSon = result[i].split("\\|");
            T obj = c.newInstance();
            Field[] fields = c.getDeclaredFields();
            for (int j = 0; j < fields.length; j++) {
                Field field = fields[j];
                field.setAccessible(true);
                String value = resultSon[j];
                //获取 clazz 类型中的 propertyName 的属性描述器
                PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(c, field.getName());
                Method setMethod = pd.getWriteMethod();//从属性描述器中获取 set 方法
                setMethod.invoke(obj, new Object[]{value});//调用 set 方法将传入的value值保存属性中去
            }
            list.add(obj);
        }
        return list;
    }

    private void copyPropertyByCustomAnno(Object target, Object src) {
        try {
            Field[] srcfields = src.getClass().getDeclaredFields();
            for (int i = 0; i < srcfields.length; i++) {
                Field field = srcfields[i];
                if (field.isAnnotationPresent(ApiFieldAnnotation.class)) {
                    field.setAccessible(true);
                    String value = (field.get(src) == null || field.get(src).equals("")) ? "空(null)" : field.get(src).toString();
//                    DecimalFormat df = new DecimalFormat("###,###.##");
//                    if (field.getAnnotation(ApiFieldAnnotation.class).fieldClassType() == BigDecimal.class) {
//                        long money = Long.valueOf(value) / 100;
//                        value = df.format(money);
//                    }

                    //获取 clazz 类型中的 propertyName 的属性描述器
                    PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(target.getClass(), field.getName());
                    Method setMethod = pd.getWriteMethod();//从属性描述器中获取 set 方法
                    setMethod.invoke(target, new Object[]{value});//调用 set 方法将传入的value值保存属性中去
                }
            }
            Field[] srcSupfields = src.getClass().getSuperclass().getDeclaredFields();
            for (int j = 0; j < srcSupfields.length; j++) {
                Field field = srcSupfields[j];
                if (field.isAnnotationPresent(ApiFieldAnnotation.class)) {
                    field.setAccessible(true);
                    String value = field.get(src) == null ? "空(null)" : field.get(src).toString();
                    //获取 clazz 类型中的 propertyName 的属性描述器
                    PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(target.getClass(), field.getName());
                    Method setMethod = pd.getWriteMethod();//从属性描述器中获取 set 方法
                    setMethod.invoke(target, new Object[]{value});//调用 set 方法将传入的value值保存属性中去
                }
            }
        } catch (Exception e) {
            log.error("获取渤海银行字段失败。", e);
        }

    }

    /**
     * 解析银行存管Pojo
     */
    private List<ReturnPojo> bhbkParseToReturnPojo(Object pojo) {
        try {
            List<ReturnPojo> params = Lists.newArrayList();
            Field[] fields = pojo.getClass().getDeclaredFields();
            Field[] fieldsSup = pojo.getClass().getSuperclass().getDeclaredFields();
            Field[] fieldsAll = new Field[fields.length + fieldsSup.length];
            for (int i = 0; i < fields.length; i++) {
                fieldsAll[i] = fields[i];
            }
            for (int j = fields.length; j < fields.length + fieldsSup.length; j++) {
                fieldsAll[j] = fieldsSup[j - fields.length];
            }
            params.addAll(bhbkParseToReturnPojo(fieldsAll, pojo));
            return params;
        } catch (Exception e) {
            log.error("解析银行存管Pojo失败。", e);
            return new ArrayList<ReturnPojo>();
        }

    }

    private List<ReturnPojo> bhbkParseToReturnSonPojo(Object pojo) {
        try {
            List<ReturnPojo> params = Lists.newArrayList();
            Field[] fields = pojo.getClass().getDeclaredFields();

            params.addAll(bhbkParseToReturnPojo(fields, pojo));
            return params;
        } catch (Exception e) {
            log.error("解析银行存管Pojo失败。", e);
            return new ArrayList<ReturnPojo>();
        }


    }

    private List<ReturnPojo> bhbkParseToReturnPojo(Field[] fields, Object pojo) {
        try {
            List<ReturnPojo> params = Lists.newArrayList();
            for (Field field : fields) {
                if (!field.isAnnotationPresent(ApiFieldAnnotation.class)
//                    || "sign".equals(field.getName())
                        ) {
                    continue;
                }
                ApiFieldAnnotation annotation = field.getAnnotation(ApiFieldAnnotation.class);
                field.setAccessible(true);
                ReturnPojo returnPojo;
                if (field.getAnnotation(ApiFieldAnnotation.class).fieldClassType() == BigDecimal.class) {
                    returnPojo = new ReturnPojo(field.getName(), annotation.fieldDesc() + "(元)", annotation.notNull(), field.get(pojo));

                } else {
                    returnPojo = new ReturnPojo(field.getName(), annotation.fieldDesc(), annotation.notNull(), field.get(pojo));
                }
                params.add(returnPojo);
            }
            return params;
        } catch (Exception e) {
            log.error("解析银行存管Pojo失败。", e);
            return new ArrayList<ReturnPojo>();
        }

    }

    @Data
    @AllArgsConstructor
    private class ReturnPojo {
        private String name;
        private String nameZh;
        private Boolean notNullFlag;
        private Object defaultValue;
    }
public class BhbkQueryChargeDetailBackPojo extends BhbkBasePojo {
    @ApiFieldAnnotation(fieldClassType = String.class, fieldDesc = "大额充值账号", notNull = false, maxLength = 32)
    private String chargeAccount;
    @ApiFieldAnnotation(fieldClassType = String.class, fieldDesc = "大额充值账户户名", notNull = false, maxLength = 128)
    private String accountName;
    @ApiFieldAnnotation(fieldClassType = String.class, fieldDesc = "可用余额", notNull = false, maxLength = 16)
    private String avlBal;
    @ApiFieldAnnotation(fieldClassType = String.class, fieldDesc = "账户余额", notNull = false, maxLength = 16)
    private String acctBal;
    @ApiFieldAnnotation(fieldClassType = String.class, fieldDesc = "冻结余额", notNull = false, maxLength = 16)
    private String frzBal;
}


ps:泛型能否代替object?

泛型的作用是为了参数的统一,Object不仅仅是这个功能,它是整个面向对象编程思维的基础,泛型是更好的开发方案!

泛型比object更好,体现在:泛型可以在编译期间检查类型错误,获得ide的上下文提示、无需运行时反射和转换,效率更高、编写的代码语义清晰更容易理解