当前位置: 首页 > 后端技术 > Java

Java反射机制实战(与泛型一起使用)

时间:2023-04-01 23:44:22 Java

Java反射是java的一个极其重要的高级特性之一。但是很多同学刚接触的时候肯定会想:这东西这么麻烦,我干嘛要用?直接用new创建一个对象不好吗?包括作者在读书的时候才知道有这么个东西。听老师说很多框架的底层都会用到反射。就这样。直到最近,笔者在项目重构中才第一次使用了反射+泛型。为此,我对反射也有一点浅薄的认识。也感受到其功能的强大。项目背景如下:对于一个电商项目,用户在获取商品信息时,可以以多个维度为切入点,比如常规的搜索功能,根据列表获取某个类目下的所有商品得到的产品。那么以获取商品列表为例:数据库中通常会有如下列表表,记录了列表id、列表名称、列表的有效时间和过期时间等。产品表记录了产品id、产品名称、产品预览图、产品链接等,列表-产品关系表记录了列表与产品的关系。通常一个列表下有多个产品。即1-n。如何将列表呈现给用户。在学校,一个常见但简单的逻辑是:后端从前端接收listid,然后在list表中查找对应的listname等,在relationship表中查找该id下的所有商品id,然后根据商品id在商品表中找到对应的信息返回给前端。但是工作之后,遇到的业务可不仅仅是几张桌子那么简单。通常需要查store表获取店铺名称,查pricelist获取商品价格,查promotion表获取促销/折扣信息,review表获取所有评论产品等等等,最后拼接所有的数据。上面加粗的业务,根据列表查询商品,根据分类查询商品,根据搜索查询商品,查询单品时都要经过一次.我原来的逻辑是:实现逻辑后,以查询单个商品为底层方法。查询其他维度的商品时,获取商品id集合后,遍历调用查询单个商品的方法。这种逻辑只有一个好处:代码复用,写起来方便。但是也有很多很多的缺点:耦合度太高,缓存设置不好,可扩展性差等等。所以当一个新需求来了之后,我发现我的逻辑不足以支持新需求的开发。于是重构了项目。重构项目时,采用了反射+泛型的方式,将粗体代码提取为公开代码。得到带有productid的List后,由于每个维度的list中的type不同(listid+other,categoryid+other),但是他们一定有一个共同的字段productId,如何提取到一个共同的类中呢?答案是使用泛型,然后使用反射获取productIdGetProductResponsegetProductResponse(Listob,GetProductRequestgetProductRequest,StringBuilderredisKey)throwsNoSuchFieldException,IllegalAccessException{//根据商品查询商品的基本信息idListtoDoList=newArrayList<>();对于(Te:ob){Fieldt=e.getClass().getDeclaredField("productId");t.setAccessible(真);StringproductId=(String)t.get(e);toDoList.addAll(getProductList(productId,getProductRequest));}//其他需要做的事情,比如查找其他字段,过滤,排序等xxxxxxxxreturnnewGetProductResponse;在前面加上,告诉jvm这是一个通用标识符,否则无法识别List。使用getClass()方法获取对应的类对象,再通过getDeclardFiled获取对应的字段。请注意,字段filed调用了setAccessible(true)方法。如果没有这行代码,私有字段在调用filed.get(T)时会报错。作者通过对公共代码的抽取,让这个公共方法成为所有维度的底层。解放了基于单一商品id的查询。要让代码更具可读性和可维护性,最重要的是结构清晰,解耦,总行数减少几百行。那么什么时候使用反射合适呢?如何使用它?作者在这里记录一个场景,欢迎大家补充其他场景。有多个维度或条目,它们的目的是相同的(目的是根据列表、分类等获取商品信息),经过处理后,它们有一个共同的字段,这个字段是下一步的关键(list和category中存放的是productId的列表,但同时除了productId,它们的其他字段是不一样的,比如listid,categoryid)和泛型一起使用。泛型的作用是让这个方法可以成为多个维度的通用底层,反射是获取泛型中的重要字段(productId)。如果读者在项目中也遇到了满足上述条件的场景,笔者这里也强烈建议大家通用的考虑反射+解耦。如果你是像笔者一样刚入门的初学者,想必你对反射也有了新的认识