• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

redis使用rightPushAll保存List,List的size为1

武飞扬头像
抹除不掉的轻狂丶
帮助1

问题描述

使用RedisTemplate保存List,期望是直接将Java的List直接转换redis的list。但是rightPushAll执行之后,却将整个list作为一个元素存到redis里面了。代码demo如下

@Controller
public class RedisTest {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @ResponseBody
    @GetMapping("/test")
    public Long test(){
     	String key = "test";
        redisTemplate.delete(key);
        ArrayList<String> arrayList = new ArrayList<>();
        arrayList.add("1");
        arrayList.add("2");
        arrayList.add("3");
        Long size = redisTemplate.opsForList().rightPushAll(key, arrayList); 
        //output 1
        System.out.println(redisTemplate.opsForList().size(key));
        List<Object> range = redisTemplate.opsForList().range(key, 0, -1);
        //output [[1, 2, 3]]
        System.out.println(range);
        return size;
    }
}
学新通

执行想要的结果是size=3,list=[1, 2, 3]。但是执行的结果却是size=1,list=[[1, 2, 3]]

问题定位

rightPushAll有两个重载方法:第一个方法values形参的接收参数是一个可变长度的泛型参数列表,第二个方法values形参的接收参数是泛型的Collection。

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.ListOperations#rightPushAll(java.lang.Object, java.lang.Object[])
	 */
	@Override
	public Long rightPushAll(K key, V... values) {

		byte[] rawKey = rawKey(key);
		byte[][] rawValues = rawValues(values);
		return execute(connection -> connection.rPush(rawKey, rawValues));
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.ListOperations#rightPushAll(java.lang.Object, java.util.Collection)
	 */
	@Override
	public Long rightPushAll(K key, Collection<V> values) {

		byte[] rawKey = rawKey(key);
		byte[][] rawValues = rawValues(values);
		return execute(connection -> connection.rPush(rawKey, rawValues));
	}
学新通

因为调用方法实参values是一个List,从语法上来说,两个重载方法是都可以调到的。因为重载是Java编译时的多态性,那么编译器编译时会调用哪个方法呢?实参ArrayList实现了Collection接口,所以误认为会走rightPushAll(K key, Collection<V> values)方法,但是Collection是带泛型的,RedisTemplate<String, Object>的value指定的泛型是Object,存值时保存的ArrayList指定的泛型却是String,虽然String继承了Object,但是编辑器编辑时还是会优先选择调用rightPushAll(K key, V... values)进行编译。可以通过打断点或者查看字节码文件验证,确实调用的是rightPushAll(K key, V... values)方法。学新通

解决方案:

RedisTemplate<K, V> 指定的value值和传入的value值的泛型类型保持一致。比如上文中的例子,只需将 private RedisTemplate<String, Object> redisTemplate;改为private RedisTemplate<String, String> redisTemplate;或者 RedisTemplate不变将ArrayList<String> arrayList = new ArrayList<>();改为ArrayList<Object> arrayList = new ArrayList<>();

问题疑惑

为什么编译器会优先走rightPushAll(K key, V... values)方法?重载的顺序到底是怎么样的?特别是泛型或者可变参数列表的形参,编译的原理是怎样的?欢迎有答案的小伙伴给我留言或者粘贴相关资料链接

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfkjhhi
系列文章
更多 icon
同类精品
更多 icon
继续加载