使用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方法,但是Collection是带泛型的,RedisTemplaterightPushAll(K key, V... values)进行编译。可以通过打断点或者查看字节码文件验证,确实调用的是rightPushAll(K key, V... values)方法。
RedisTemplateprivate RedisTemplate改为private RedisTemplate或者 RedisTemplate不变将ArrayList改为ArrayList
为什么编译器会优先走rightPushAll(K key, V... values)方法?重载的顺序到底是怎么样的?特别是泛型或者可变参数列表的形参,编译的原理是怎样的?欢迎有答案的小伙伴给我留言或者粘贴相关资料链接