我对物理结构的一点点理解,不知道靠谱吗?为什么要序列化?是不是就是因为对象在物理结构里的关系?这东西看不见摸不着,我想举个例子来形容下,我们知道内存条里都是一个单元一个单元的挨着的地址空间对吧,那数据首先是存内存里的,但是,数据不会是按着内存条里的一个单元一个单元的按着顺序去存的,其实这么说不太对,是可以这么存,但也可以不这么存,我们把这些不同方式保存数据的方式叫物理结构?之所以有时候不安顺序保存是为了提高查找数据或者删除数据 遍历数据 什么的能提高效率,所以不能都是一种按顺序存储。于是有了
集合、线性结构、树形结构、图状结构等等不同的存储结构。但是无论是什么结构,对于物理内存条里的一个单元一个单元还是固定不变的,变的只是这些数据在内存里的存储方式,这就是我想要具体了解下的东东。我举个例子,比如一个内存条里有100个单元地址,一个挨着一个的。我有10个苹果标号1-10吧(苹果就是数据)我可以一个一个的按顺序保存在内存里。比如:
1234567890(假设这是1-10个苹果的数据)
但是如果我要找10号苹果,那程序要一个一个从第一个开始按顺序找,很麻烦,影响效率。但是如果我换个方法存,又比如13579          24680
这就不是按顺序结构在内存存的,假设这也是一种物理结构,假如我起名为单双结构!
专门用来处理单数和双数查找用的,那以后有需要查找单数或者双数的就用这种结构肯定比上面的顺序结构提高效率,因为上面的要从头到尾找10次,而我这种只找5次就找到了10号苹果,把单号省略了一半!那我们可以看出,内存单元没有变还是一个一个的地址,变化的是存储数据的方式,有人说数据方式怎么变了?是这么变的,我们把系统分配给程序的内存总空间分成2部分了,一部分用来存单数,一部分用来存双数,这不就是数据结构吗,上面的是不分内存统一连续存放,下面这个是单双结构,分开存储数据。看你要实现具体的功能来才取不同的数据结构!这就是我对数据结构的理解!不知道靠谱嘛。。
如有不对,还望纠正!通过这个问题,我想我就明白了序列化这个概念,为什么要序列化,就是因为java虚拟机对对象在内存里的组织安排,所以才序列化,因为对象可能在内存里被单独或者按某个格式存放,目的就是为了让虚拟机处理的时候更便捷,如果我们不序列化,那么保存文件后,虚拟机下次读取的时候,就不知道那个是对象了,那就没法在内存里进行对象的安排了,不能安排对象了,那效率就降低了,所以保存文件之前,弄个序列化的意思就是把哪些是对象,相当于做个标记,然后等下次读取的时候,看到这个标记我就知道,哦这小子是个对象,我要把它放到某某个内存区里单独保存。这样就不至于什么数值啊 变量啊 有用没用的都混在一起了。我感觉好像就是这个意思。但是对于普通的文本文件来说,里面没有涉及到对象的东东,保存的时候可能不需要徐序列化吧,毕竟文本文件里都是一堆文字而已,对于这些字符串保存时候又有必要每次保存读取都序列化吗?

解决方案 »

  1.   

    以下内容为转载
    =====================================================================
    Java序列化的机制和原理
    2009-08-28 10:18 longdick longdick的博客 我要评论(1) 字号:T | T本文讲解了Java序列化的机制和原理。从文中你可以了解如何序列化一个对象,什么时候需要序列化以及Java序列化的算法。
    AD: 有关Java对象的序列化和反序列化也算是Java基础的一部分,下面对Java序列化的机制和原理进行一些介绍。
    Java序列化算法透析
    Serialization(序列化)是一种将对象以一连串的字节描述的过程;反序列化deserialization是一种将这些字节重建成一个对象的过程。Java序列化API提供一种处理对象序列化的标准机制。在这里你能学到如何序列化一个对象,什么时候需要序列化以及Java序列化的算法,我们用一个实例来示范序列化以后的字节是如何描述一个对象的信息的。
    序列化的必要性
    Java中,一切都是对象,在分布式环境中经常需要将Object从这一端网络或设备传递到另一端。这就需要有一种可以在两端传输数据的协议。Java序列化机制就是为了解决这个问题而产生。
    如何序列化一个对象
    一个对象能够序列化的前提是实现Serializable接口,Serializable接口没有方法,更像是个标记。有了这个标记的Class就能被序列化机制处理。
    import java.io.Serializable;  
     
    class TestSerial implements Serializable {  
     
           public byte version = 100;  
     
           public byte count = 0;  
     } 
    然后我们写个程序将对象序列化并输出。ObjectOutputStream能把Object输出成Byte流。我们将Byte流暂时存储到temp.out文件里。
    public static void main(String args[]) throws IOException {  
     
           FileOutputStream fos = new FileOutputStream("temp.out");  
     
           ObjectOutputStream oos = new ObjectOutputStream(fos);  
     
           TestSerial ts = new TestSerial();  
     
           oos.writeObject(ts);  
     
           oos.flush();  
     
           oos.close();  
     

    如果要从持久的文件中读取Bytes重建对象,我们可以使用ObjectInputStream。 
    public static void main(String args[]) throws IOException {  
     
           FileInputStream fis = new FileInputStream("temp.out");  
     
           ObjectInputStream oin = new ObjectInputStream(fis);  
     
           TestSerial ts = (TestSerial) oin.readObject();  
     
           System.out.println("version="+ts.version);  
     

    执行结果为
    100.
    对象的序列化格式
    将一个对象序列化后是什么样子呢?打开刚才我们将对象序列化输出的temp.out文件,以16进制方式显示。内容应该如下:
    AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 6573 74 A0 0C 34 00 FE B1 DD F9 02 00 02 42 00 0563 6F 75 6E 74 42 00 07 76 65 72 73 69 6F 6E 7870 00 64这一坨字节就是用来描述序列化以后的
    TestSerial对象的,我们注意到TestSerial类中只有两个域:
    public byte version = 100;
    public byte count = 0;
    且都是byte型,理论上存储这两个域只需要2个byte,但是实际上temp.out占据空间为51bytes,也就是说除了数据以外,还包括了对序列化对象的其他描述。
    Java的序列化算法
    序列化算法一般会按步骤做如下事情:
    ◆将对象实例相关的类元数据输出。
    ◆递归地输出类的超类描述直到不再有超类。
    ◆类元数据完了以后,开始从最顶层的超类开始输出对象实例的实际数据值。
    ◆从上至下递归输出实例的数据
    我们用另一个更完整覆盖所有可能出现的情况的例子来说明:
    class parent implements Serializable {  
     
           int parentVersion = 10;  
     
    }  
     
       
     
    class contain implements Serializable{  
     
           int containVersion = 11;  
     
    }  
     
    public class SerialTest extends parent implements Serializable {  
     
           int version = 66;  
     
           contain con = new contain();  
     
       
     
           public int getVersion() {  
     
                  return version;  
     
           }  
     
           public static void main(String args[]) throws IOException {  
     
                  FileOutputStream fos = new FileOutputStream("temp.out");  
     
                  ObjectOutputStream oos = new ObjectOutputStream(fos);  
     
                  SerialTest st = new SerialTest();  
     
                  oos.writeObject(st);  
     
                  oos.flush();  
     
                  oos.close();  
     
           }  
     

    这个例子是相当的直白啦。SerialTest类实现了Parent超类,内部还持有一个Container对象。
    序列化后的格式如下:
    AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65
    73 74 05 52 81 5A AC 66 02 F6 02 00 02 49 00 07
    76 65 72 73 69 6F 6E 4C 00 03 63 6F 6E 74 00 09
    4C 63 6F 6E 74 61 69 6E 3B 78 72 00 06 70 61 72
    65 6E 74 0E DB D2 BD 85 EE 63 7A 02 00 01 49 00
    0D 70 61 72 65 6E 74 56 65 72 73 69 6F 6E 78 70
    00 00 00 0A 00 00 00 42 73 72 00 07 63 6F 6E 74
    61 69 6E FC BB E6 0E FB CB 60 C7 02 00 01 49 00
    0E 63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E 78
    70 00 00 00 0B
    我们来仔细看看这些字节都代表了啥。开头部分,见颜色:
    AC ED: STREAM_MAGIC. 声明使用了序列化协议.
    00 05: STREAM_VERSION. 序列化协议版本.
    0x73: TC_OBJECT. 声明这是一个新的对象. 
    序列化算法的第一步就是输出对象相关类的描述。例子所示对象为SerialTest类实例,因此接下来输出SerialTest类的描述。见颜色:
    0x72: TC_CLASSDESC. 声明这里开始一个新Class。
    00 0A: Class名字的长度.
    53 65 72 69 61 6c 54 65 73 74: SerialTest,Class类名.
    05 52 81 5A AC 66 02 F6: SerialVersionUID, 序列化ID,如果没有指定,则会由算法随机生成一个8byte的ID.
    0x02: 标记号. 该值声明该对象支持序列化。
    00 02: 该类所包含的域个数。
    接下来,算法输出其中的一个域,int version=66;见颜色:
    0x49: 域类型. 49 代表"I", 也就是Int.
    00 07: 域名字的长度.
    76 65 72 73 69 6F 6E: version,域名字描述.
    然后,算法输出下一个域,contain con = new contain();这个有点特殊,是个对象。描述对象类型引用时需要使用JVM的标准对象签名表示法,见颜色:
    0x4C: 域的类型.
    00 03: 域名字长度.
    63 6F 6E: 域名字描述,con
    0x74: TC_STRING. 代表一个new String.用String来引用对象。
    00 09: 该String长度.
    4C 63 6F 6E 74 61 69 6E 3B: Lcontain;, JVM的标准对象签名表示法.
    0x78: TC_ENDBLOCKDATA,对象数据块结束的标志
    .接下来算法就会输出超类也就是Parent类描述了,见颜色:
    0x72: TC_CLASSDESC. 声明这个是个新类.
    00 06: 类名长度.
    70 61 72 65 6E 74: parent,类名描述。
    0E DB D2 BD 85 EE 63 7A: SerialVersionUID, 序列化ID.
    0x02: 标记号. 该值声明该对象支持序列化.
    00 01: 类中域的个数.
    下一步,输出parent类的域描述,int parentVersion=100;同见颜色:
    0x49: 域类型. 49 代表"I", 也就是Int.
    00 0D: 域名字长度.
    70 61 72 65 6E 74 56 65 72 73 69 6F 6E: parentVersion,域名字描述。
    0x78: TC_ENDBLOCKDATA,对象块结束的标志。
    0x70: TC_NULL, 说明没有其他超类的标志。.
    到此为止,算法已经对所有的类的描述都做了输出。下一步就是把实例对象的实际值输出了。这时候是从parent Class的域开始的,见颜色:
    00 00 00 0A: 10, parentVersion域的值.
    还有SerialTest类的域:
    00 00 00 42: 66, version域的值.
    再往后的bytes比较有意思,算法需要描述contain类的信息,要记住,现在还没有对contain类进行过描述,见颜色:
    0x73: TC_OBJECT, 声明这是一个新的对象.
    0x72: TC_CLASSDESC声明这里开始一个新Class.
    00 07: 类名的长度.
    63 6F 6E 74 61 69 6E: contain,类名描述.
    FC BB E6 0E FB CB 60 C7: SerialVersionUID, 序列化ID.
    0x02: Various flags. 标记号. 该值声明该对象支持序列化
    00 01: 类内的域个数。
    .输出contain的唯一的域描述,int containVersion=11;
    0x49: 域类型. 49 代表"I", 也就是Int..
    00 0E: 域名字长度.
    63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E: containVersion, 域名字描述.
    0x78: TC_ENDBLOCKDATA对象块结束的标志.
    这时,序列化算法会检查contain是否有超类,如果有的话会接着输出。
    0x70:TC_NULL,没有超类了。
    最后,将contain类实际域值输出。
    00 00 00 0B: 11, containVersion的值.
    OK,我们讨论了java序列化的机制和原理,希望能对同学们有所帮助。
    本文来自longdick的博客:《Java序列化算法透析》
      

  2.   


    我觉得你说的顺序排列是效率最高的好像不对,如果你不从头找,万一漏掉一个怎么办?再说你并不知道10具体在哪个位置对吧?你不遍历整个序列怎么找到10?而且物理上的存储和逻辑上的结构我感觉是一一对应的,应该有关系,不然你拿什么结构控制让内存帮你安排更方便更便捷的存储方式?肯定是先用逻辑结构编排好,然后在通知物理地址哪个地方存哪个数,哪个地方不存,哪个地方空着,正是有了这样的规律存储数据,我们才能按照这种特殊规律对数据进行更好的操作!当然这是我的个人理解,还请权威人士来肯定才成-。-你说的找苹果是这个意思啊,那没有错,这算是逻辑层面的数据结构的好处,不过跟物理上的连续存储还是关系不大吧。
    我所能想到的,除了数组必须连续存储外,好像其它数据结构都是用指针定位的,也就是跟具体存储位置没有关系。
    举个例子,用两条链表实现你说的找苹果,单数号一条,双数号一条,每个结点包含【一个苹果】和【下一个苹果的地址】连续存储的情形:
    【1号苹果】【位置3】-->【3号苹果】【位置5】-->【5号苹果】【位置7】-->【7号苹果】【位置9】-->【9号苹果】【null】
    【2号苹果】【位置4】-->【4号苹果】【位置6】-->【6号苹果】【位置8】-->【8号苹果】【位置10】-->【10号苹果】【null】分开存储的情形:
    【1号苹果】【位置2】-->【3号苹果】【位置3】-->【5号苹果】【位置4】-->【7号苹果】【位置5】-->【9号苹果】【null】
    【2号苹果】【位置2】-->【4号苹果】【位置3】-->【6号苹果】【位置4】-->【8号苹果】【位置5】-->【10号苹果】【null】你说,这两者有区别吗?
      

  3.   


    我觉得你说的顺序排列是效率最高的好像不对,如果你不从头找,万一漏掉一个怎么办?再说你并不知道10具体在哪个位置对吧?你不遍历整个序列怎么找到10?而且物理上的存储和逻辑上的结构我感觉是一一对应的,应该有关系,不然你拿什么结构控制让内存帮你安排更方便更便捷的存储方式?肯定是先用逻辑结构编排好,然后在通知物理地址哪个地方存哪个数,哪个地方不存,哪个地方空着,正是有了这样的规律存储数据,我们才能按照这种特殊规律对数据进行更好的操作!当然这是我的个人理解,还请权威人士来肯定才成-。-你说的找苹果是这个意思啊,那没有错,这算是逻辑层面的数据结构的好处,不过跟物理上的连续存储还是关系不大吧。
    我所能想到的,除了数组必须连续存储外,好像其它数据结构都是用指针定位的,也就是跟具体存储位置没有关系。
    举个例子,用两条链表实现你说的找苹果,单数号一条,双数号一条,每个结点包含【一个苹果】和【下一个苹果的地址】连续存储的情形:
    【1号苹果】【位置3】-->【3号苹果】【位置5】-->【5号苹果】【位置7】-->【7号苹果】【位置9】-->【9号苹果】【null】
    【2号苹果】【位置4】-->【4号苹果】【位置6】-->【6号苹果】【位置8】-->【8号苹果】【位置10】-->【10号苹果】【null】分开存储的情形:
    【1号苹果】【位置2】-->【3号苹果】【位置3】-->【5号苹果】【位置4】-->【7号苹果】【位置5】-->【9号苹果】【null】
    【2号苹果】【位置2】-->【4号苹果】【位置3】-->【6号苹果】【位置4】-->【8号苹果】【位置5】-->【10号苹果】【null】你说,这两者有区别吗?我好像明白你的意思了,你是说数据结构是在逻辑层面就弄好了,到了物理结构还是一个一个存,只是有个可能顺序全打乱了,但是逻辑结构那里不会乱,而且树形结构 线性结构什么的都是在逻辑层排好的,到时候利用指针跳着在内存里找数就行了?是这个意思吧?但是内存里还是连续存的数据。
    我原来的想法是这样分开存的,比如内存地址单元有1-10个地址空间,正好对应10个苹果,把单数的苹果通过逻辑结构处理好后,物理地址的1-5存的是13579号,而物理地址里6-10存的是24680号,这样如果我们找10号苹果,根据我们用的这种单双分开数据结构(打个比方哦),那经过判断得到10是一个双号,那就通知指针从双号开始的位置开始遍历所有双数!也就是指针直接从物理地址6开始遍历,经过5次的遍历找到最后的10!嗯我理解的这种,好像跟你说的一样,还是你说的对,跟物理上的存储关系不大,就像我说的,单数都排前面了,然后双数都排后面了,这样分开了就好查找了,确实是没错,但是在内存里还是一个一个的排列保存的,这就是你说的跟物理上的连续存储关系不大 呵呵。准确的说,应该说是在物理上数据还是连续的存储,只是每个数据可能顺序不同 或者位置不同等等,这根据逻辑层结构来安排,这么说我觉得就好多了吧
      

  4.   


    我觉得你说的顺序排列是效率最高的好像不对,如果你不从头找,万一漏掉一个怎么办?再说你并不知道10具体在哪个位置对吧?你不遍历整个序列怎么找到10?而且物理上的存储和逻辑上的结构我感觉是一一对应的,应该有关系,不然你拿什么结构控制让内存帮你安排更方便更便捷的存储方式?肯定是先用逻辑结构编排好,然后在通知物理地址哪个地方存哪个数,哪个地方不存,哪个地方空着,正是有了这样的规律存储数据,我们才能按照这种特殊规律对数据进行更好的操作!当然这是我的个人理解,还请权威人士来肯定才成-。-你说的找苹果是这个意思啊,那没有错,这算是逻辑层面的数据结构的好处,不过跟物理上的连续存储还是关系不大吧。
    我所能想到的,除了数组必须连续存储外,好像其它数据结构都是用指针定位的,也就是跟具体存储位置没有关系。
    举个例子,用两条链表实现你说的找苹果,单数号一条,双数号一条,每个结点包含【一个苹果】和【下一个苹果的地址】连续存储的情形:
    【1号苹果】【位置3】-->【3号苹果】【位置5】-->【5号苹果】【位置7】-->【7号苹果】【位置9】-->【9号苹果】【null】
    【2号苹果】【位置4】-->【4号苹果】【位置6】-->【6号苹果】【位置8】-->【8号苹果】【位置10】-->【10号苹果】【null】分开存储的情形:
    【1号苹果】【位置2】-->【3号苹果】【位置3】-->【5号苹果】【位置4】-->【7号苹果】【位置5】-->【9号苹果】【null】
    【2号苹果】【位置2】-->【4号苹果】【位置3】-->【6号苹果】【位置4】-->【8号苹果】【位置5】-->【10号苹果】【null】你说,这两者有区别吗?我好像明白你的意思了,你是说数据结构是在逻辑层面就弄好了,到了物理结构还是一个一个存,只是有个可能顺序全打乱了,但是逻辑结构那里不会乱,而且树形结构 线性结构什么的都是在逻辑层排好的,到时候利用指针跳着在内存里找数就行了?是这个意思吧?但是内存里还是连续存的数据。
    我原来的想法是这样分开存的,比如内存地址单元有1-10个地址空间,正好对应10个苹果,把单数的苹果通过逻辑结构处理好后,物理地址的1-5存的是13579号,而物理地址里6-10存的是24680号,这样如果我们找10号苹果,根据我们用的这种单双分开数据结构(打个比方哦),那经过判断得到10是一个双号,那就通知指针从双号开始的位置开始遍历所有双数!也就是指针直接从物理地址6开始遍历,经过5次的遍历找到最后的10!嗯我理解的这种,好像跟你说的一样,还是你说的对,跟物理上的存储关系不大,就像我说的,单数都排前面了,然后双数都排后面了,这样分开了就好查找了,确实是没错,但是在内存里还是一个一个的排列保存的,这就是你说的跟物理上的连续存储关系不大 呵呵。准确的说,应该说是在物理上数据还是连续的存储,只是每个数据可能顺序不同 或者位置不同等等,这根据逻辑层结构来安排,这么说我觉得就好多了吧你想表达的意思,其实说白了就是数组,我前面说了,数组的确是要求物理上连续存储的,你这个找苹果的例子,如果用数组来实现的话,就是建立两个数组,而由于数组连续存储,所以实际上这两堆苹果确实是分离的,你的例子没有错
    但这仅仅是对于数组,数据结构还有其它很多,你看换成链表的话物理层和逻辑层就没有关系了
    可以这么说,你这个例子之所以成立,只是由于数组的访问特性,对于采用指针的数据结构,不管物理上连续还是分离,顺序还是乱序,怎么放都是没关系的
      

  5.   


    我觉得你说的顺序排列是效率最高的好像不对,如果你不从头找,万一漏掉一个怎么办?再说你并不知道10具体在哪个位置对吧?你不遍历整个序列怎么找到10?而且物理上的存储和逻辑上的结构我感觉是一一对应的,应该有关系,不然你拿什么结构控制让内存帮你安排更方便更便捷的存储方式?肯定是先用逻辑结构编排好,然后在通知物理地址哪个地方存哪个数,哪个地方不存,哪个地方空着,正是有了这样的规律存储数据,我们才能按照这种特殊规律对数据进行更好的操作!当然这是我的个人理解,还请权威人士来肯定才成-。-你说的找苹果是这个意思啊,那没有错,这算是逻辑层面的数据结构的好处,不过跟物理上的连续存储还是关系不大吧。
    我所能想到的,除了数组必须连续存储外,好像其它数据结构都是用指针定位的,也就是跟具体存储位置没有关系。
    举个例子,用两条链表实现你说的找苹果,单数号一条,双数号一条,每个结点包含【一个苹果】和【下一个苹果的地址】连续存储的情形:
    【1号苹果】【位置3】-->【3号苹果】【位置5】-->【5号苹果】【位置7】-->【7号苹果】【位置9】-->【9号苹果】【null】
    【2号苹果】【位置4】-->【4号苹果】【位置6】-->【6号苹果】【位置8】-->【8号苹果】【位置10】-->【10号苹果】【null】分开存储的情形:
    【1号苹果】【位置2】-->【3号苹果】【位置3】-->【5号苹果】【位置4】-->【7号苹果】【位置5】-->【9号苹果】【null】
    【2号苹果】【位置2】-->【4号苹果】【位置3】-->【6号苹果】【位置4】-->【8号苹果】【位置5】-->【10号苹果】【null】你说,这两者有区别吗?我好像明白你的意思了,你是说数据结构是在逻辑层面就弄好了,到了物理结构还是一个一个存,只是有个可能顺序全打乱了,但是逻辑结构那里不会乱,而且树形结构 线性结构什么的都是在逻辑层排好的,到时候利用指针跳着在内存里找数就行了?是这个意思吧?但是内存里还是连续存的数据。
    我原来的想法是这样分开存的,比如内存地址单元有1-10个地址空间,正好对应10个苹果,把单数的苹果通过逻辑结构处理好后,物理地址的1-5存的是13579号,而物理地址里6-10存的是24680号,这样如果我们找10号苹果,根据我们用的这种单双分开数据结构(打个比方哦),那经过判断得到10是一个双号,那就通知指针从双号开始的位置开始遍历所有双数!也就是指针直接从物理地址6开始遍历,经过5次的遍历找到最后的10!嗯我理解的这种,好像跟你说的一样,还是你说的对,跟物理上的存储关系不大,就像我说的,单数都排前面了,然后双数都排后面了,这样分开了就好查找了,确实是没错,但是在内存里还是一个一个的排列保存的,这就是你说的跟物理上的连续存储关系不大 呵呵。准确的说,应该说是在物理上数据还是连续的存储,只是每个数据可能顺序不同 或者位置不同等等,这根据逻辑层结构来安排,这么说我觉得就好多了吧你想表达的意思,其实说白了就是数组,我前面说了,数组的确是要求物理上连续存储的,你这个找苹果的例子,如果用数组来实现的话,就是建立两个数组,而由于数组连续存储,所以实际上这两堆苹果确实是分离的,你的例子没有错
    但这仅仅是对于数组,数据结构还有其它很多,你看换成链表的话物理层和逻辑层就没有关系了
    可以这么说,你这个例子之所以成立,只是由于数组的访问特性,对于采用指针的数据结构,不管物理上连续还是分离,顺序还是乱序,怎么放都是没关系的那咱们抛开数组这个不说,假如换个别的结构,物理层和逻辑层没有关系,就是物理上你不说分离 乱序 怎么放都行,这个我明白了,我是说这样放的话,算不算也是一个单元一个单元的乱放?
    我现在的意思是说内存是个硬件,它的结构肯定是固定的对吧,一个单元一个单元的,不会变对吧。
    你现在要乱序的放,也没事,我是说虽然打乱了顺序了,但是在内存地址里还是不是一个挨着一个的存?比如12345苹果  内存地址1-5
    按你说的咱们乱序放:53214(分别对应的内存地址还是1-5,我指的是这个意思,这个地址不还是连续的存嘛,只是苹果的顺序乱了而已)
    还是可以这么存的:内存地址1对应苹果5  内存地址2空着 内存地址3空着 内存地址4对应苹果1 地址5对应苹果2 地址6对应苹果3 地址7空着 后面省略...(还是这样跳着存乱序的也行?那空着的内存会不会有点浪费了?)
      

  6.   

    这个问题,其实在硬盘存储上更典型
    我一个5KB的文件A,后面紧挨着放了另一个文件B,这时候我打开文件A加了几行,再保存的时候怎么办?就超过5KB了,就顶到前面文件B的屁股上了,假如文件必须连续存储,这个时候只能在硬盘上其它地方找一块足够大的新地方,把整个文件A剪切到那里去,这个开销是很大的
    实际上的做法是,在文件A的结尾加个记号,告诉系统,我这文件还没完,后面还有,你到XXXX地址去读后半部分,跟链表差不多