程序时常要和各种数据打交道,合理地组织数据的结构以及相关操作是程序设计的一个重要方面,比如在程序设计中经常会使用诸如链表、散列表等数据结构。下图是常用的几种数据结构:
以前学习数组,在数组中我们可以存储整型类型、字符类型等,但并没有存储过复杂的数据类型,诸如对象。上述的这七个容器不仅可以储存基本的数据,也可以存储复杂的数据类型。
比如举个例子,现在有个Student类,把其对象s1、s2、s3存到HashSet集合中,需要先构造一个存储Student对象的容器
Set<Student> hashset = new HashSet<Student>();这时,就可以利用Set的一些方法对其进行操作了。
下面说说这几种容器的特点吧。
Set集合的主要特点及用法
- 里面的元素不重复,如果加入了一个里面已有的元素,会覆盖原先的元素。
- 只允许里面有一个 null 元素
- 里面的元素是没有顺序的,但是,TreeSet根据是否实现 Comparator 或者 Comparable 来确定元素的顺序,例如String类实现了元素以ASCII码进行排序,因此,当存储到TreeSet中,在同一层的结点从左到右、从上到下,会排好序。
- HashSet直接实现了Set接口,并继承AbstractSet抽象类(AbstractSet抽象类实现了Set接口)
- TreeSet直接实现NavigableSet接口(NavigableSet接口继承SortedSet接口),并继承AbstractSet抽象类(AbstractSet抽象类实现了Set接口)
- LinkedHashSet直接实现Set接口,并继承HashSet类。底层采用双向链表实现,可以保证元素的插入顺序,又因为是HashSet的子类,所以插入的元素不能重复。
常用方法:
- boolean addAll(Collection<? extends E> c):如果c中的元素在集合中不存在,把所有元素加入集合
- void clear():从该集中删除所有元素
- boolean contains(Object o):如果此set包含指定的元素,则返回true
- boolean containsAll(Collection<?> c):如果此set包含指定collection的所有元素,则返回true。
- boolean isEmpty():判断是否为空
- boolean remove(Object o):如果元素存在,则从该集合中移除指定的元素
- boolean removeAll(Collection<?> c):从此集合中删除指定集合中包含的所有元素
- int size():返回此集合中的元素数
List的主要特点及用法
- 允许存储重复的对象
- 可以插入多个null元素
- 是一个有序容器,保持了每一个元素的插入顺序,插入的顺序即输出的顺序
- ArrayList类直接实现List接口,继承AbstractList抽象类,默认ArrayList的长度是10个.
- LinkedList类直接实现List接口,继承AbstractSequentialList抽象类(AbstractSequentialList抽象类继承AbstractList抽象类),它更适合用在经常需要添加删除元素的场景中。
- Vector类实现List接口,继承AbstractList抽象类
常用方法:
boolean add(E e):将指定的元素追加到此列表的末尾
void add(int index, E element):将指定元素插入此列表中的指定位置
boolean addAll(Collection<? extends E> c):将指定集合追加到末尾
void clear():从此列表中删除所有元素
boolean contains(Object o):如果此列表包含指定的元素,则返回true
boolean containsAll(Collection<?> c):如果此列表包含指定集合的所有元素,则返回true
E get(int index):返回此列表中指定位置的元素
boolean isEmpty():如果此列表不包含任何元素,则返回true
int indexOf(Object o):返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1
int lastIndexOf(Object o):返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回-1
E remove(int index):删除此列表中指定位置的元素
boolean remove(Object o):从该列表中删除第一次出现的指定元素(如果存在)
boolean removeAll(Collection<?> c):从此列表中删除指定集合中包含的所有元素
int size():返回此列表中的元素数
void sort(Comparator<? super E> c):根据指定的顺序对此列表进行排序
Map集合的主要特点及用法
- Map接口和Collection接口及其实现类没有任何关系
- Map是以键值对的形式存在,即一个元素是entry,其中包括[key:value],是无序的。
- Map键值对的键不允许重复,如果出现两个相同的键,那么,先前散列映射中的键/值对将被替换。
- Map 里你可以拥有随意个 null 值,即key和value的值允许为null,但最多只能有一个key为null
- HashMap类实现Map接口,继承AbstractMap抽象类,它的实现不是同步的,这意味着它不是线程安全的。
- Hashtable类实现Map接口,继承Dictionary抽象类,它的实现是同步的,所以是线程安全的。
- TreeMap 也通过 Comparator 或者 Comparable 维护了一个排序顺序 ,通过红黑树实现,它保证结点是按照结点中的关键字升序排列。
- LinkedHashMap类实现Map接口,继承HashMap
常用方法:
void clear():清空散列映射
boolean containsKey(Object key):如果此散列映射包含指定键的映射,则返回true
boolean containsValue(Object value):如果此散列映射的value包含一个或多个指定参数,则返回true
Set<Map.Entry<K,V>> entrySet():返回包含散列映射视图Set集合
V get(Object key):返回指定键映射到的值
boolean isEmpty():判断散列映射是否为空
Set<K> keySet():返回散列映射键的Set集合
V put(K key, V value):将指定的值与此映射中的指定键相关联
V remove(Object key):如果存在键,则从该映射中移除键值对
boolean remove(Object key, Object value):删除键-值为指定参数的映射
Collection<V> values():返回散列映射值的Collection集合
int size():返回此映射中键 - 值的数量
Vector和ArrayList区别
LinkedList和ArrayList区别
- ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
- 对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
- 对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
- ArrayList内部是使用可増长数组实现的,所以是用get和set方法是花费常数时间的,但是如果插入元素和删除元素,除非插入和删除的位置都在表末尾,否则代码开销会很大,因为里面需要数组的移动。
- LinkedList是使用双链表实现的,所以get会非常消耗资源,除非位置离头部很近。但是插入和删除元素花费常数时间。
HashMap补充
HashMap对象采用散列表这种数据结构存储数据。HashMap 的实例有两个参数影响其性能:“初始容量” 和 “加载因子”。容量 是哈希表中桶的数量,初始容量 只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。
通常,默认加载因子是 0.75, 这是在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数 HashMap 类的操作中,包括 get 和 put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。
Map的三种遍历方法
- 使用keySet创建迭代器遍历“键”
- 使用public Collection<V> values()方法返回一个实现Collection<V>接口类创建的对象,创建迭代器获取“值”
- 使用entrySet创建迭代器遍历键值对
- 使用普通for循环遍历“键”
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class PrintMap {
public static void main(String args[]) {
Map<String,Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
map.put("d", 4);
map.put("e", 5);
System.out.println("//使用keySet");
Iterator iterator1 = map.keySet().iterator();
while (iterator1.hasNext()) {
Object key= iterator1.next();
System.out.println(key + ":"+map.get(key));
}
System.out.println("使用Collection接口,获取value");
Collection c = map.values();
Iterator iterator2= c.iterator();
while (iterator2.hasNext()) {
Object value = iterator2.next();
System.out.println(value);
}
System.out.println("//使用entrySet创建迭代器遍历键值对");
Iterator iterator3=map.entrySet().iterator();
while (iterator3.hasNext()) {
Map.Entry entry = (Map.Entry) iterator3.next();
Object key = entry.getKey();
Object value=entry.getValue();
System.out.println(key +":"+value);
}
System.out.println("//使用foreach循环获取键");
for (String key : map.keySet()) {
System.out.println(key + ":"+map.get(key));
}
}
}