三歪:真没想到,竟然上次面试还有问注解的

    三歪:我面了这么多次,第一次碰到,还好我表现得足够机智,哈哈哈哈。

    三歪:话又说回来,能在真实项目中勇于去写自定义注解来优化代码的人,真的是人才

    三歪:为了奖励下自己,点杯卡布奇洛喝一把

    三歪:面试官,请问现在可以开始了吗

    面试官:嗯,开始吧。

    面试官:这次咱们就来聊聊泛型呗?你对泛型有多少了解?

    三歪:在Java中的泛型简单来说就是:在创建对象或调用方法的时候才明确下具体的类型

    三歪:使用泛型的好处就是代码更加简洁(不再需要强制转换),程序更加健壮(在编译期间没有警告,在运行期就不会出现ClassCastException异常)

    面试官:平时在工作中用得多吗?

    三歪:在操作集合的时候,还是很多的,毕竟方便啊。

    1. List<String> lists = new ArrayList<>();
    2. lists.add("面试造火箭");

    面试官:还有其他的场景写过吗?

    三歪:如果是其他场景的话,那就是在写「基础组件」的时候了。

    面试官:来,说说背景吧,你是怎么写的。

    三歪:再明确一下泛型就是「在创建对象或调用方法的时候才明确下具体的类型」,而组件为了做到足够的通用性,是不知道「用户」传入什么类型参数进来的,所以在这种情况下用泛型就是很好的实践。

    三歪:这块可以参考SpringData JPAJpaRepository写法。

    1. public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
    2. List<T> findAll();
    3. List<T> findAll(Sort sort);
    4. List<T> findAllById(Iterable<ID> ids);
    5. <S extends T> List<S> saveAll(Iterable<S> entities);
    6. void flush();
    7. <S extends T> S saveAndFlush(S entity);
    8. void deleteInBatch(Iterable<T> entities);
    9. void deleteAllInBatch();
    10. T getOne(ID id);
    11. @Override
    12. <S extends T> List<S> findAll(Example<S> example);
    13. @Override
    14. <S extends T> List<S> findAll(Example<S> example, Sort sort);
    15. }

    三歪:要写组件,还是离不开Java反射机制(能够从运行时获取信息),所以一般组件是泛型+反射来实现的。

    三歪:回到我所讲的组件吧,背景是这样的:我这边有个需求,需要根据某些字段进行聚合。

    三歪:换到 SQL 其实就是 select sum(column1),sum(column2) from table group by field1,field2

    三歪:应该很好理解吧?

    面试官:插入表情包

    三歪:需要 sum 和group by 的列肯定是由业务方自己传入,而SQL 的表 其实就是我们的POJO(传入的字段也肯定是 POJO 的属性)

    三歪:单个业务实际可以在参数上写死POJO,但为了做得更加通用,我把入参设置为泛型

    三歪:拿到参数后,通过反射获取其字段具体的值,做累加就好了。

    1. // 传入 需要group by 和 sum 的字段名
    2. public cacheMap(List<String> groupByKeys, List<String> sumValues) {
    3. this.groupByKeys = groupByKeys;
    4. this.sumValues = sumValues;
    5. }
    6. private void excute(T e) {
    7. // 从pojo 取出需要group by 的字段 list
    8. List<Object> key = buildPrimaryKey(e);
    9. // primaryMap 是存储结果的Map
    10. T value = primaryMap.get(key);
    11. // 如果从存储结果找到有相应记录
    12. if (value != null) {
    13. for (String elem : sumValues) {
    14. // 反射获取对应的字段,做累加处理
    15. Field field = getDeclaredField(elem, e);
    16. if (field.get(e) instanceof Integer) {
    17. field.set(value, (Integer) field.get(e) + (Integer) field.get(value));
    18. } else if (field.get(e) instanceof Long) {
    19. field.set(value, (Long) field.get(e) + (Long) field.get(value));
    20. } else {
    21. throw new RuntimeException("类型异常,请处理异常");
    22. }
    23. }
    24. // 处理时间记录
    25. Field field = getDeclaredField("updated", value);
    26. if (null != field) {
    27. field.set(value, DateTimeUtils.getCurrentTime());
    28. }
    29. } else {
    30. // group by 字段 第一次进来
    31. try {
    32. primaryMap.put(key, Tclone(e));
    33. createdMap.put(key, DateTimeUtils.getCurrentTime());
    34. }catch (Exception ex) {
    35. log.info("first put value error {}" , e);
    36. }
    37. }
    38. }

    三歪:理解了泛型的作用之后,再去审视自己代码时,就可以判断是否需要用到泛型了。

    面试官:嗯,可以的,总体来看有自己的见解。

    三歪:主要是在平时工作中,写代码的时候会多想想,遇到能用到的地方会优化下代码

    面试官:今天面试到这里就已经结束了,你有什么想问我的吗?

    三歪:面试官您看我有机会吗?

    面试官:有的,小伙子,等消息吧,过几天我会继续面你的。