关于list和String

发布网友 发布时间:2022-04-23 10:13

我来回答

6个回答

懂视网 时间:2022-04-13 11:46

Redis源码解析4 - 数据类型之 String List STRING string类型的数据在Redis中有两种编码方式: 1.RAW 这表示一个原始字符串对象,robj中的ptr指针指向一个sds类型的内存块 sds是一个带长度信息的内存块,用于存储 二进制安全 的字符串 2. INT 这表示一个编码

Redis源码解析4 - 数据类型之 String & List

STRING

string类型的数据在Redis中有两种编码方式:

1. RAW
这表示一个原始字符串对象,robj中的ptr指针指向一个sds类型的内存块
sds是一个带长度信息的内存块,用于存储二进制安全的字符串

2. INT
这表示一个编码为整数的字符串对象,robj中的ptr指针被强行转化为一个long型变量以存储整数
数字类型的字符串,比如“123456”,都会被编码为整型
这样做的目的就一点,节省内存。就以字符串“123456”为例,
(1) 存为RAW类型,共消耗内存为:sizeof(robj) + sizeof(sdshdr) + strlen("123456")
32位系统为26字节,位系统下为30字节
(2) 存为INT类型,共消耗内存为:sizeof(robj)
32位系统为12字节,位系统下为16字节

可以看出,节省的内存还是挺多的
如果字符串更长一些,比如“1234567”,节省的内存就可观了

一点小提示,在Redis中,位的bigint,虚拟主机,是按RAW格式存储的
之所以这么做,完全是为了兼容不同的系统
在实际使用中,如果你确定你的机器都是位的(MS现在很少32位机了),可以改改源代码,多节省一些内存

再加一幅图,更直观的说明一下

OK,在Redis中,String是最基本的类型,也很简单,从上图可以较清晰的看出String的组织方式了

题外话,不知道有同学注意到没有,robj中的ptr居然是指向sdshdr内存块的中间部分,而不是指向内存头

从这一点看,Redis的代码也挺“野”的

LIST

list数据有两种编码方式:

1. linked_list
这就是一个传统的双向链表,带头尾指针,其头尾操作都只有O(1)的复杂度

2. ziplist
这是一种压缩编码的链表,它将所有的链表数据全部整合进一整块内存中,相比传统的链表,节省很多内存

简要说明一下上图:

(1) ziplist使用一整块连续的内存,这块内存由三部分组成:
(a) head块,链表的头信息,包括有 totalsize(链表总长度)、tailoffset(尾部最后一个元素的偏移字节数)、entrycount(entry个数)
(b) entry块,由一系列的 entry node 组成。node之间紧凑排列
每个node有 prevsize字段,表示前一个node的长度,用以反方向索引
有selfsize字段,表示当前node的长度
以及data字段,存放当前node的实际数据
这些字段都按一种特殊的形式编码,具体参考上图,已经比较清晰了
(c) tail块,虚拟主机,链表的尾部。只有一个字节,是一个填充码。

(2) 向ziplist中增删元素时,有较频繁的内存重分配操作,服务器,以及较复杂的数值运算
所以,当链表长度增加时,整个数据结构就会不堪重负

(3) redis用两个阀值来控制 ziplist 与 linked_list 之间的转换
(a) list_max_ziplist_entries:当链表元素的个数超过该值,自动转化为 linked_list,该值默认512
(b) list_max_ziplist_value:当链表中某个字符串元素的长度超过该值,自动转化为 linked_list,该值默认
(c) 以上两值均可通过配置文件修改

posted on

热心网友 时间:2022-04-13 08:54

程序中一般使用的是List的实现类ArrayList
数组是JAVA语言内置的数据类型,它是一个线性的序列,所以它可以快速的访问其他的元素。但是速度是要有代价的,当你创建了一个数组之后,它的容量就固定了,而且在其生命周期里是不能改变的。还有一点,JAVA里面的数组是会做边界检查的,所以当你越界访问时,会抛出RuntimeException,当然边界检查是以牺牲效率为代价的。数组与其它容器类的区别体现在三个方面:效率、类型识别和可以持有primitives。

1.效率:
数组扩容是对ArrayList效率影响比较大的一个因素。
每当执行Add、AddRange、Insert、InsertRange等添加元素的方法,都会检查内部数组的容量是否不够了,如果是,它就会以当前容量的两倍来重新构建一个数组,将旧元素Copy到新数组中,然后丢弃旧数组,

在这个临界点的扩容操作,应该来说是比较影响效率的。

ArrayList是Array的复杂版本
ArrayList内部封装了一个Object类型的数组,从一般的意义来说,它和数组没有本质的差别,甚至于

ArrayList的许多方法,如Index、IndexOf、Contains、Sort等都是在内部数组的基础上直接调用Array的对应方法。

2.类型识别:
ArrayList存入对象时,抛弃类型信息,所有对象屏蔽为Object,编译时不检查类型,但是运行时会报错。

注:jdk5中加入了对泛型的支持,已经可以在使用ArrayList时进行类型检查。

从这一点上看来,ArrayList与数组的区别主要就是由于动态增容的效率问题了

3.ArrayList可以存任何Object,如String,Employee等,但不支持基本数据类型,除非使用wrapper。

建议:
首先使用数组,无法确定数组大小时才使用ArrayList!

热心网友 时间:2022-04-13 10:12

很简单
从数据库里面查询的时候不知道有多少条记录返回,这种情况用数组,定义数组必须确定长度,如String[] [] ary = new String[2][4];
但是list就不用考虑具体长度。

对于只有一条记录的或者返回数据条数一定的,用数组还会快一点,所以这种情况定义string[]完全可以。追问应该不会这么简单吧!
而且我可以通过
rs.last();
int rowCount=rs.getRow();
rs.beforeFirst();
ResultSetMetaData rsmd=rs.getMetaData();
int colCount=rsmd.getColumnCount();
这几句得到行数和列数的!

追答问题是你这样就复杂很多了,逻辑上明显没有LIST方便。

而且如果要排序的话,list可以直接调用Collections.sort(list), ,比数组代码简单多了

热心网友 时间:2022-04-13 11:47

1楼、2楼讲的都不错
不用考虑长度,不用每次都去获取结果集的长度
存取方便,如果一条记录有30-40个字段或者更多,你记得住那么多字段与索引的对应关系吗,或者是取值的时候看着一张映射表?
不能否认,字符串数组在数据量比较小的时候比较方便
但是当对象粒度比较大时,列表就是比较好的选择了
使用字符数组固然能完成任务,同时列表能够更好地利用对象,减少工作量

热心网友 时间:2022-04-13 13:38

list<表实体> 的话,String就没法达到,并且如果数据库查寻出来的字段不能确定,用list接收也不String好多的多。在list中可以保存对象,实则用的范型,而在String中只能保存String类型的,如果是日期,number,float等,甚至可以是对象中的属性等。而String就太狭隘了,比如得到数据后要返回json格式数据,list就可以达到要求,返回到页面得到json格式数据并且解析出来,而String则片面返回一个几维String型而已,要想构建成json格式,并在页面根据属性取出对应值,就难之又难了

热心网友 时间:2022-04-13 15:46

其他的先不管,至少用二维数据存放数据在取出来的时候很麻烦,而list取出来很方便啊 ,而且数组要确定具体长度,但list是可变数组,不需要考虑这些情况,而且在页面显示的时候,list都和这些标签有配套,可以很快遍历,但数组貌似就不怎么方便了追问是吗?list如果取一维数组方便我信,取二维就未必了吧。list.get(i);
String[i][j]只用指定下标就可以!

追答list它的底层原理其实就是用数组实现的,只不过把数组包装了一层,所以它和数组是没多大的区别的是,可能最大的区别就在于一个是可变的,一个是不可变的,其他的基本差不多,你去这个地址看看吧,http://blog.sina.com.cn/s/blog_5ce1fe770100b0ay.html,当然你喜欢用哪一种是由你自己决定,不过用集合的话在页面显示的时候要方便点
还有一点是list提供了删除元素的方法,而数组没有

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com