数组
- 数组是一种最基础的数据结构
- 数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。
- 第一是线性表(Linear List)
数据排成像一条线一样的结构。除了数组,链表、队列、栈等也是线性表结构。
非线性表,比如二叉树、堆、图等。非线性表中,数据之间并不是简单的前后关系 - 第二个是连续的内存空间和相同类型的数据。正是因为这两个限制,它才有了一个堪称“杀手锏”的特性:“随机访问”。但有利就有弊,这两个限制也让数组的很多操作变得非常低效,比如要想在数组中删除、插入一个数据,为了保证连续性,就需要做大量的数据搬移工作。即便是排好序的数组,你用二分查找,时间复杂度也是O(logn)
- 数组支持随机访问,根据下标随机访问的时间复杂度为O(1)
- 先记录下已经删除的数据。每次的删除操作并不是真正地搬移数据,只是记录数据已经被删除。当数组没有更多空间存储数据时,我们再触发执行一次真正的删除操作,这样就大大减少了删除操作导致的数据搬移。
- 访问数组的本质就是访问一段连续内存,只要数组通过偏移计算得到的内存地址是可用的,那么程序就可能不会报任何错误。
- ArrayList最大的优势就是可以将很多数组操作的细节封装起来。比如前面提到的数组插入、删除数据时需要搬移其他数据等。另外,它还有一个优势,就是支持动态扩容。
- 如何选择数组还是容器
1.Java ArrayList无法存储基本类型,比如int、long,需要封装为Integer、Long类,而Autoboxing、Unboxing则有一定的性能消耗,所以如果特别关注性能,或者希
望使用基本类型,就可以选用数组。
2.如果数据大小事先已知,并且对数据的操作非常简单,用不到ArrayList提供的大部分方法,也可以直接使用数组。
3.当要表示多维数组时,用数组往往会更加直观。比如Object[][] array;而用容器的话则需要这样定ArrayList array。
我总结一下,对于业务开发,直接使用容器就足够了,省时省力。毕竟损耗一丢丢性能,完全不会影响到系统整体的性能。如果你是做一些非常底层的开发,比如开发网络框架,性能的优化需要做到极致,这个时候数组就会优于容器,成为首选。 - “下标”最确切的定义应该是“偏移(offset)”
- 大多数主流虚拟机采用可达性分析算法来判断对象是否存活,在标记阶段,会遍历所有 GC ROOTS,将所有 GC ROOTS 可达的对象标记为存活。只有当标记工作完成后,清理工作才会开始。
不足:1.效率问题。标记和清理效率都不高,但是当知道只有少量垃圾产生时会很高效。2.空间问题。会产生不连续的内存空间碎片。 - 二维数组内存寻址:
对于 m * n 的数组,a [ i ][ j ] (i < m,j < n)的地址为:
address = base_address + ( i * n + j) * type_size - 对于不同的编译器,在内存分配时,会按照内存地址递增或递减的方式进行分配。根据不同的递减方式,数组越界有可能会造成死循环。