Java的基本数据结构如下:
Collection
|-List
|-ArrayList
|-Vector
|-LinkedList
|-Set
|-HashSet
|-TreeSet
List与Set都是集成了Collection接口的子接口,下面的具体实现类对其中的抽象方法进 列表内容
List的最大特点是有序,但是存储元素不唯一。
ArrayList的底层数据结构是数组,在进行遍历或查询时,只需要移动指针即可访问到下一个元素。但是如果我们想增加某些元素,增加到array[i]位置上,先要将i之后的所有元素都向后移位,将i位置空出来才能把新元素放进去,这个操作非常耗时。删除也是同理,需要将被删除元素后的所有元素都向前移位,填补空缺。因此查询快,增删慢。线程不安全,速度快。
Vector的底层数据结构是数组,因此也具有查询快,增删慢的特点。其线程是不安全的,速度快。
LinkedList的底层数据结构是链表,其特点是存储的数据分为两部分,数据部分和指针部分。数据部分包含的是你要存储的数据,指针部分包含的是下一个元素所在的内存地址。所以如果某些数据是以链表的形式存储的,它在内存中不像ArrayList是占用一整块内存空间,二是在分布在内存中,通过指针部分来找到下一个元素。同时也有双向链表这种既可以找到下一个元素也可以找到上一个元素的数据结构。其最大的特点就是当你增删的时候,只需要修改前后元素的指针部分,就可以完成增加和删除。但如果我们想遍历链表,就需要不停的获取下一个元素地址值,然后去寻址,这就非常耗时。因此LinkedList查询慢,增删快。其线程不安全,速度快。
Set的最大特点就是保证存入元素是唯一的,即不重复。
HashSet的底层数据结构是哈希表,调用add()方法进行添加时,通过被添加对象的hashcode()方法和equals()进行判断,确认被添加元素是否已经出现在hashset中。其存储方式如下图:
hashcode: 0 1 2 ...
| | |
存储元素地址: 0x001 0x002 0x003
| |
0x004 0x005
每一个hashcode对应一个链表,首先通过hashcode()计算出该元素的哈希值,然后找到对应的链表,再通过equals和链表中的每一个元素进行对比,如果没有重复的就进行添加。
因此我们在重写hashcode()方法时,应该使hashcode尽可能的不同,这样就会减少调用equals()方法的次数,从而提高运行速度。
TreeSet的底层数据结构是红黑树(自平衡二叉树),使用迭代器或增强for循环遍历出来的元素是有序的,这个顺序不是我们存入的顺序,而是通过Comparable接口的compareTo()方法或Comparator接口的compare()方法判断出的顺序。
同样,TreeSet也可以保证存入的元素是唯一的,其存储方式如下图所示:
我们在实际使用的时候最重要的一点就是仔细的判断两个元素相同的条件,否则在使用时,某些应该被存储的元素就会被漏掉。