Collection是集合框架层次结构中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。Collection接口下有最常用的接口为List跟Set。需要注意的是,Map并没有实现Collection接口。
List接口实现类ArrayList
优点:类似数组的形式进行存储,因此它的随机访问速度极快。
缺点:不适合于在线性表中间需要频繁进行插入和删除操作。因为每次插入和删除都需要移动数组中的元素,它是用数组存储元素的,这个数组可以动态创建,如果元素个数超过了数组的容量,那么就创建一个更大的新数组,并将当前数组中的所有元素都复制到新数组中。
public class ArrayListTest {
public static void main(String[] args){
List arrayList=new ArrayList();
arrayList.add("Welcome");
arrayList.add("to");
arrayList.add("java");
//把ArrayList变为数组相关的内容进行遍历
String[] strArray=new String[arrayList.size()];
arrayList.toArray(strArray);
for(int i=0;i iter=arrayList.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
}
}
优点:适合于在链表中间需要频繁进行插入和删除操作。
缺点: 随机访问速度较慢。查找一个元素需要从头开始一个一个的找。此类实现 Deque 接口,为 add、poll 提供先进先出队列操作,以及其他堆栈和双端队列操作LinkedList是在一个链表中存储元素。
public class LinkedListTest {
public static void main(String[] args){
List linkedList=new LinkedList();
//使用ForEach遍历linkedList
String[] strArray2=new String[linkedList.size()];
linkedList.toArray(strArray2);
for(int i=0;i iter=linkedList.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
}
}
List接口实现类Vector:
Vector使用了关键字synchronized将访问和修改向量的方法都变成同步的了,所以对于不需要同步的应用程序来说,类ArrayList比类Vector更高效。
相同点:
①都继承于AbstractList,并且实现List接口
②都实现了RandomAccess和Cloneable接口
③都是通过数组实现的,本质上都是动态数组,默认数组容量是10
④都支持Iterator和listIterator遍历
不同点:
①ArrayList是非线程安全,而Vector是线程安全的
②容量增加方式不同,Vector默认增长为原来一倍,而ArrayList却是原来的一半+1
③Vector支持通过Enumeration去遍历,而List不支持
public class VectorTest {
public static void main(String[] args){
Vector vector = new Vector();
for(int i = 0; i < 10; i++){
vector.add(i);
}
//直接打印
System.out.println(vector.toString());
//size()
System.out.println(vector.size());
//contains
System.out.println(vector.contains(2));
//总结:对比Vector的遍历方式,使用索引的随机访问方式最快,使用迭代器最慢
//iterator遍历
Iterator iterator = vector.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next() + " ");
}
//Enumeration遍历
Enumeration enu = vector.elements();
while (enu.hasMoreElements()) {
System.out.println((Integer)enu.nextElement());
}
//toArray
Object[] objArr = vector.toArray();
System.out.println("\nobjArr:" + Arrays.asList(objArr));
Integer[] intArr = vector.toArray(new Integer[vector.size()]);
System.out.println("intArr:" + Arrays.asList(intArr));
//add
vector.add(5);
//remove
vector.remove(5);
System.out.println(vector);
//containsAll
System.out.println(vector.containsAll(Arrays.asList(5,6)));
//addAll
vector.addAll(Arrays.asList(555,666));
System.out.println(vector);
//removeAll
vector.removeAll(Arrays.asList(555,666));
System.out.println(vector);
//addAll方法
vector.addAll(5, Arrays.asList(666,666, 6));
System.out.println(vector);
//get方法
System.out.println(vector.get(5));
//set方法
vector.set(5, 55);
System.out.println(vector.get(5));
//add方法
vector.add(0, 555);
System.out.println(vector);
//remove方法
vector.remove(0);
System.out.println(vector);
//indexof方法
System.out.println(vector.indexOf(6));
//lastIndexOf方法
System.out.println(vector.lastIndexOf(6));
//listIterator方法
ListIterator listIterator = vector.listIterator();
System.out.println(listIterator.hasPrevious());
//listIterator(index)方法
ListIterator iListIterator = vector.listIterator(5);
System.out.println(iListIterator.previous());
//subList方法
System.out.println(vector.subList(5, 7));
//clear
vector.clear();
System.out.println(vector);
}
}
List接口实现类Stack
栈类,是Java2之前引入的,继承自类Vector。同样是线程同步的
public class StackTest {
public static void main(String[] args){
Stack stack = new Stack();
for(int i = 0; i < 10; i++){
stack.add(i);
}
System.out.println(stack);
System.out.println(stack.peek());
stack.push(555);
System.out.println(stack);
System.out.println(stack.pop());
System.out.println(stack);
System.out.println(stack.empty());
System.out.println(stack.search(6));
System.out.println("stack遍历:");
while(!stack.empty()){
System.out.print(stack.pop() + " ");
}
}
}
List接口总结:实际使用中我们需要根据特定的需求选用合适的类,如果 除了在末尾外不能在其他位置插入或者删除元素,那么ArrayList效率更高,如果需要经常插入或者删除元素,就选择LinkedList。
Set接口实现类HashSet:
HashSet是Set接口最常见的实现类,其底层是基于hash算法进行存储相关元素的。HashSet中存储元素的位置是固定的(由hashCode决定),并且是无序的。Set集合中的去重和hashCode与equals方法相关。
public class Num implements Comparable{
private int num;
public Num(int num){
this.num=num;
}
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
Num x=(Num)o;
if(num>x.num)return 1;
else if(num==x.num) return 0;
else return -1;
}
public String toString(){
return "num="+num;
}
}
public class HashSetTest {
public static void main(String[] args){
Set hashSet=new HashSet();
hashSet.add("hello");
hashSet.add("world");
hashSet.add("world");
//使用数组的方法遍历HashSet集合
String[] strArray=new String[hashSet.size()];
strArray=hashSet.toArray(strArray);
for(String str:strArray){
System.out.println(str);
}
//使用HashSet集合直接遍历
for(String str:hashSet){
System.out.println(str);
}
//用迭代器遍历HashSet集合
Iterator iterator=hashSet.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
//无重写hashCode跟equals方法的类,不会自动根据类中的值进行去重
Set set2=new HashSet();
set2.add(new Num(1));
set2.add(new Num(3));
set2.add(new Num(2));
set2.add(new Num(3));
set2.add(new Num(3));
set2.add(new Num(6));
System.out.println(set2.size());
Iterator iterator2=set2.iterator();
while(iterator2.hasNext()){
System.out.println(iterator2.next());
}
}
}
LinkedHashSet继承HashSet,是用一个链表实现来扩展HashSet类,它支持对规则集内的元素排序。HashSet中的元素是没有被排序的,而LinkedHashSet中的元素可以按照它们插入规则集的顺序提取。
public class LinkedHashSetTest {
public static void main(String[] args){
Set linkedHashSet=new LinkedHashSet();
linkedHashSet.add("hello");
linkedHashSet.add("world");
linkedHashSet.add("world");
//使用数组的方法遍历HashSet集合
String[] strArray=new String[linkedHashSet.size()];
strArray=linkedHashSet.toArray(strArray);
for(String str:strArray){
System.out.println(str);
}
//使用HashSet集合直接遍历
for(String str:linkedHashSet){
System.out.println(str);
}
//用迭代器遍历HashSet集合
Iterator iterator=linkedHashSet.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
TreeSet实现了Set接口,它与HashSet的区别主要在于TreeSet中的元素会按照相关的值进行排序。HashSet是通过HashMap实现的,TreeSet是通过TreeMap实现的,只不过Set用的只是Map的key。由于TreeMap需要排序,所以需要一个Comparator为键值进行大小比较.当然也是用Comparator定位的.如果创建时没有确定,那么就会使用key.compareTo()方法,这就要求key必须实现Comparable接口.TreeMap是使用Tree数据结构实现的,所以使用compare接口就可以完成定位了.
注意:TreeSet是根据对象的CompareTo方法来去重的,如果CompaerTo返回0说明两个对象相等,不能同时存在于TreeSet中。
public class TreeSetTest {
public static void main(String[] args){
Set treeSet=new TreeSet();
treeSet.add("d");
treeSet.add("c");
treeSet.add("b");
treeSet.add("a");
//String实体类中实现Comparable接口,所以在初始化TreeSet的时候,
//无需传入比较器
Iterator iterator=treeSet.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
Set treeSet2=new TreeSet();
treeSet2.add(new Num(1));
treeSet2.add(new Num(3));
treeSet2.add(new Num(2));
treeSet2.add(new Num(3));
treeSet2.add(new Num(3));
treeSet2.add(new Num(6));
System.out.println(treeSet2.size());
Iterator iterator2=treeSet2.iterator();
while(iterator2.hasNext())
{
System.out.println(iterator2.next());
}
TreeSet set = new TreeSet<>();
set.add(1111);
set.add(2222);
set.add(3333);
set.add(4444);
set.add(5555);
System.out.println(set.first()); // 输出第一个元素
System.out.println(set.lower(3333)); //小于3333的最大元素
System.out.println(set.higher(2222)); //大于2222的最大元素
System.out.println(set.floor(3333)); //不大于3333的最大元素
System.out.println(set.ceiling(3333)); //不小于3333的最大元素
System.out.println(set.pollFirst()); //删除第一个元素
System.out.println(set.pollLast()); //删除最后一个元素
System.out.println(set);
}
}
Set接口区别于List接口在于:
所有Set中的元素实现了不重复,有点像数学中集合的概念,无序,不允许有重复的元素,最多允许有一个null元素对象
Map接口:
Map接口储存一组成对的键-值对象,提供key(键)到value(值)的映射,Map中的key不要求有序,不允许重复。value同样不要求有序,但可以重复。
Map实现类HashMap
最常见的Map实现类,他的储存方式是哈希表,优点是查询指定元素效率高。HashMap采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当链表中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,HashMap采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
无论什么情况HashMap中哈希表的容量总是2的n次方的一个数。并且有这样一个公式:当length=2^n时,hashcode & (length-1) == hashcode % length
HashMap与Hashtable的区别:
Hashtable实现Map接口,继承自古老的Dictionary类,实现一个key-value的键值映射表。任何非空的(key-value)均可以放入其中。 区别主要有三点:
1.Hashtable是基于陈旧的Dictionary实现的,而HashMap是基于Java1.2引进的Map接口实现的;
2.Hashtable是线程安全的,而HashMap是非线程安全的,我们可以使用外部同步的方法解决这个问题。
3.HashMap可以允许你在列表中放一个key值为null的元素,并且可以有任意多value为null,而Hashtable不允许键或者值为null。
public class HashMapTest {
public static void main(String[] args){
Map hashMap=new HashMap();
hashMap.put("a",1);
hashMap.put("b",2);
hashMap.put("JAVA",3);
System.out.println(hashMap.get("JAVA"));
//第一种遍历方法:普遍使用,二次取值
for (String key : hashMap.keySet()) {
System.out.println("key= "+ key + " and value= " + hashMap.get(key));
}
//第二种:通过Map.entrySet使用iterator遍历key和value
Iterator> iter=hashMap.entrySet().iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
//第三种:通过Map.entrySet遍历key和value.推荐,尤其是容量大时
for (Map.Entry entry : hashMap.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第四种:通过Map.values()遍历所有的value,但不能遍历key
for (Integer v : hashMap.values()) {
System.out.println("value= " + v);
}
}
}
LinkedHashMap继承自HashMap,它主要是用链表实现来扩展HashMap类,HshMap中条目是没有顺序的,但是在LinkedHashMap中元素既可以按照它们插入图的顺序排序,也可以按它们最后一次被访问 的顺序排序。LinkedHashMap继承自HashMap并且实现了Map接口。和HashMap一样,LinkedHashMap 允许key和value均为null。于该数据结构和HashMap一样使用到hash算法,因此它不能保证映射的顺序,尤其是不能保证顺序持久不变(再哈希)。
public class LinkedHashMapTest {
public static void main(String[] args){
Map linkedHashMap=new LinkedHashMap();
linkedHashMap.put("a", 1);
linkedHashMap.put("java",2);
linkedHashMap.put("C", 3);
System.out.println(linkedHashMap.get("a"));
Set> entry=linkedHashMap.entrySet();
Iterator> iter=entry.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
Set keySet=linkedHashMap.keySet();
for(String x:keySet){
System.out.println(x+"="+linkedHashMap.get(x));
}
}
}
TreeMap基于红黑树数据结构的实现,键值可以使用Comparable或Comparator接口来排序。TreeMap继承自AbstractMap,同时实现了接口NavigableMap,而接口NavigableMap则继承自SortedMap。SortedMap是Map的子接口,使用它可以确保图中的条目是排好序的。 TreeMap默认是根据key升序排序,同TreeSet一样,TreeMap默认是升序的key-value的key是根据Comparable实现的方法CompareTo的返回值来去重的。
public class TreeMapTest {
public static void main(String[] args){
Map treeMap=new TreeMap();
treeMap.put("b",2);
treeMap.put("a",1);
treeMap.put("e",5);
treeMap.put("d",4);
treeMap.put("c",3);
Set> entry=treeMap.entrySet();
Iterator> iter=entry.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
Set keySet=treeMap.keySet();
for(String x:keySet){
System.out.println(x+"="+treeMap.get(x));
}
Map treeMap2=new TreeMap();
treeMap2.put(new Num(2),"a");
treeMap2.put(new Num(1),"b");
treeMap2.put(new Num(5),"c");
treeMap2.put(new Num(4),"d");
treeMap2.put(new Num(3),"c");
Set keySet2=treeMap2.keySet();//根据compareTo方法去重
for(Num x:keySet2){
System.out.println(x+"="+treeMap2.get(x));
}
//根据value排序
Map map = new HashMap();
map.put("d", 2);
map.put("c", 1);
map.put("b", 4);
map.put("a", 3);
List> infoIds =
new ArrayList>(map.entrySet());
//排序前
for (int i = 0; i < infoIds.size(); i++) {
String id = infoIds.get(i).toString();
System.out.println(id);
}
//排序
Collections.sort(infoIds, new Comparator>() {
public int compare(Map.Entry o1, Map.Entry o2) {
return (o2.getValue() - o1.getValue());
//return (o1.getKey()).toString().compareTo(o2.getKey());
}
});
//排序后
for (int i = 0; i < infoIds.size(); i++) {
String id = infoIds.get(i).toString();
System.out.println(id);
}
}
}
Map接口总结:在实际使用中,如果更新图时不需要保持图中元素的顺序,就使用HashMap,如果需要保持图中元素的插入顺序或者访问顺序,就使用LinkedHashMap,如果需要使图按照键值排序,就使用TreeMap。