Java_集合框架

Posted zeotoone

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java_集合框架相关的知识,希望对你有一定的参考价值。


编程时,常常需要集中存放多个数据。可以使用数组来保存,但一旦初始化时指定了数组的长度,数组就不可变了。而集合类就很好的解决了这一问题。Java集合大致可分为 Set、List、Queue、Map四种体系。Java集合框架图:

【简图】

  • Set 不可重复集合 {HashSet, TreeSet}
  • List 有序,重复集合 {ArrayList, LinkedList, Vector}
  • Map 具有映射关系 key-value集合 {HashMap, TreeMap, HashTable}
  • Queue、Deue 队列集合 {PriorityQueue, ArrayDeue}

注:顺序分为 自然排序[a-z], 添加元素的排序

一、Collection 和 迭代器

Collection接口是 List、Set和 Queue 接口的父接口

  • 迭代器 Iterator 和 Enumeration

迭代器: Enumeration<E> 接口被 Iterator <E>替代。它的实现类StringTokenizer

Enumeration e  = new StringTokenizer("A-B-C","-");
while(e.hasMoreElements()){ // 是否还有元素
	System.out.println(e.nextElement());  //返回下一个元素
}

// Arrays.asList(T...a)返回的是一个T List<T> 类型的new ArrayList<>(a)对象
// 这个ArrayList<E> 是定义在Arrays中的私有类部类,且有一个带 E[] a 参数
Collection c = Arrays.asList("a","n","b");
Iterator it = c.iterator();
for( ;it.hasNext();)
    System.out.println(it.next());
  • ListIterator 接口
    • 允许双向遍历list
    • 在遍历时修改List元素
    • 遍历时获取迭代器当前游标所在位置
List l = Arrays.asList("a","n","b");
ListIterator lit = l.listIterator();
while(lit.hasNext()){
    System.out.println(lit.next());
}
while(lit.hasPrevious()){
    System.out.println(lit.previous());
}
// foreach 是通过迭代器来实现
for (Object aL : l) {
    System.out.println(aL);
}

二、List 接口与实现类

  • List
    List是一个有序可重复的集合,常用的List实现类 ArrayList, LinkedList和Vector。List接口实现类在实现插入元素时,都会根据索引进行排列,会改变其他元素的位置。

  • AbstractList
    继承 AbstractCollection 抽象类,实现了 List 接口 ,是 ArrayList 和 AbstractSequentiaList 的父类。AbstractList 内部已经提供了 Iterator, ListIterator 迭代器的实现类Itr ,ListItr。

  • ArrayList、LinkedList、Vector

1-- ArrayList 使用数组方式存储数据(本质上是一个数组),y有初始容量大小 ,超容时自动扩容为原来的1.5倍。线程是不安全的。增删效率低,查询效率高。
防止不同步访问列表:List list = Collections.synchronizedList(new ArrayList(...));

ArrayList<String> al = new ArrayList<String>(5); //指定容量大小
al.ensureCapacity(10); // 增加容量
al.add("Hello"); // 元素可重复
al.add("Hello");
al.add("word");
al.set(1, "Two"); // 替换索引为1 的元素
al.add("four");
al.trimToSize();
al.remove(3); // 删除索引为 3 的元素
System.out.println(al.toArray().length);
System.out.println(al.size()); //3 元素个数
System.out.println(al.get(1)); //Two 获取 index=0 的元素
//System.out.println(al.get(3)); // index=3 的元素被删除,报错

2-- LinkedList双向链表,实现了List和 Deque接口。与ArrayList一样也是线程不安全。双向链表,不存在元素限制,没有扩容机制。其查询效率差,增删效率高。

LinkedList<String> ll = new LinkedList<String>();
ll.add("adb"); // 元素可重复
ll.add("adb");
ll.add(1," ");  // 内部通过遍历删除ll.remove(" ");
ll.add("shell");
ll.addFirst("<"); // 列表开头插入指定的元素 对应的删除 ll.removeFirst();
ll.addLast(">"); // 列表结尾插入指定的元素  对应的删除 ll.removeLast();
ll.remove(3); // 删除 index=3 的元素
for(Object l: ll){
    System.out.print(l); // <adb shell> 遍历输出列表元素
    // ll.listIterator(); // 正向迭代
    //ll.descendingIterator(); // 反向迭代
}
ll.push("shell"); //实质上就是将元素插入到开头位置 addFirst()
System.out.println("\\n"+ll.get(0)); // 内部通过遍历查找 index=0 的元素 或者 ll.getFirst();
System.out.println(ll.element()); // 内部调用 getFirst()
System.out.println(ll.pop()); // 内部调用 removeFirst()
ll.clear(); // 清除列表所有元素

3-- Vector类实现了可扩展的对象数组,与ArrayList一样有初始容量大小,超容会自动扩容为原来的2倍,但线程是安全的。所以增删查询效率比ArrayList差一些。

Vector<Integer> v = new Vector<Integer>();
// Vector 继承AbstractCollection 重写的 toString() 方法
System.out.println(v); // 打印[] 与 ArrayList 一样
v.add(1);
v.addElement(2);
v.insertElementAt(129, 1);
for(Object o: v)
    System.out.println(o); // 1 \\n 129 \\n 4 迭代 Vector 中的元素
//v.setSize(19);// 设置元素个数的大小
//System.out.println(v.capacity()); // 20
v.trimToSize();  //将容量大小变为所包含元素个数大小
System.out.println(v.capacity()); // 3   当前列表的容量大小
v.clear();
if(v.isEmpty()) System.out.println("none ");

三、Map 接口与实现类

  • Map 接口
    Map将键映射到值的对象,不能包含重复的键。Map 中元素的顺序取决于迭代器迭代时的顺序,有的实现类(TreeMap)保证了元素输入输出时的顺序,有的实现类(HashMap)则是无序的 .

  • AbstractMap 抽象类
    AbstractMap 提供了 Map 的基本实现。该抽象类中只有一个抽象方法public abstract Set<Entry<K,V>> entrySet();

  • HashMap、TreeMap、 HashTable

1-- HashMap 采用哈希表实现的键值对集合,底层实现链表数组(jdk1.8加入红黑树).有默认初始容量,扩容由容量和加载因子(0.75)决定。非线程安全的。

HashMap<String, String> m = new HashMap<String, String>();
m.put("1","zzz"); // key不能重复,value可以
m.put("2","zzz");
m.put("0","");
m.put(null,"111"); // 不打印该键值,被最后为null的键覆盖
m.put("4",null);
m.put(null,null); // key,value允许空值
Set<String> s =m.keySet();
for(Object o: s){ // 迭代输出 map中的 keys
    System.out.println("key:" + o);
}
Collection c = m.values();
for(Object o: c){ // 迭代输出 map中的 values
    System.out.println("value:" + o);
}
// 迭代map
for(Map.Entry<String, String> entry: m.entrySet()){
    System.out.println(entry.getKey()+"--->"+entry.getValue());
}

2-- TreeMap 基于红黑树实现,按自然顺序或自定义顺序遍历键(key),键不能为null, 非线程安全

TreeMap<String, String> tm = new TreeMap<String, String>();
tm.put("1","22");
//tm.put(null,null); // 键不能为null, 会抛出空指针异常
tm.put("","");
tm.put("2",null);
tm.put("0","22");
System.out.println(tm.replace("","1"));// 替换对应key的值
for(Map.Entry<String, String> entry: tm.entrySet()){
    System.out.println(entry.getKey()+"--->"+entry.getValue());
}
System.out.println("value:"+tm.get("")); // 通过key获取 value
System.out.println("first key:" +tm.firstKey() +" ,value:"+ tm.lastKey()); // 获取第一个key - value
System.out.println(tm.higherKey("2")); //大于给定键的小键,不存在则返回 null
System.out.println(tm.tailMap("0")); // 返回其键大于等于 key的键值
System.out.println(tm.ceilingKey("2")); //大于或等于给定键的键
System.out.println(tm.lowerKey("2")); // 小于给定键的最大键,如果没有则返回 nul

3-- HashTable是散列表,继承Dictionary抽象类直接实现了Map接口。键和值都不能为 null,线程安全

Hashtable<String, String> ht = new Hashtable<String, String>();
 ht.put("","");
 //ht.put(null,"");  // 键不能为 null
 //ht.put("1",null); // 值也不能为 null
 ht.put("1","a");
 ht.put("2","b");
 ht.put("0","c");
 ht.put("3","d");
 Enumeration e = ht.elements();//可以使用Enumeration 迭代器
 for(Map.Entry<String, String> entry: ht.entrySet()){
     System.out.println(entry.getKey()+"--->"+entry.getValue());
 }

四、Set 接口与实现类

  • Set 接口
    Set是一个不可重复的集合,允许包含值为null的元素。

  • AbstractSet 抽象类
    继承 AbstractCollection 抽象类,实现了 Set 接口。与AbstractList 不同,AbstractSet类中只有3 个方法 equals、hashCode、removeAll。其add,remove,clear ... 都是子类自己实现。

  • HashSet、TreeSet

1-- HashSet继承AbstractSet抽象类,直接实现了Set接口。无序列集合,并且多线程不安全。底层通过HashMap实现,Map中key不能重复,这也就是Set不允许重复的原因。

HashSet<String> hs = new HashSet<String>();
String str = new String("abc");
hs.add(null);
hs.add("abc");
hs.add(str); // 重复元素
hs.add("");
System.out.println(hs.size()); // 3 元素个数
// forEach 内部通过 for(T t:this){} 实现,调用的是Iterable接口(即 Collection接口的父类)中的方法,
hs.forEach(System.out::println); // 等同于 o -> System.out.println(o)
hs.removeAll(hs); // 调用父类的方法删除所有元素
hs.addAll(Arrays.asList("a","a","b")); // 将指定集合中的所有元素添加到此集合,可用于去重

2-- TreeSet继承AbstractSet抽象类,实现NavigableSet接口,而该接口继承了SortedSet最后才继承Set接口。使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法。

TreeSet<String> ts = new TreeSet<String>();
ts.add("aaa0"); // 迭代时,按自然排序输出 [1, 2, 3, 4, aaa, aaa0, begin, end]
ts.add("aaa");
ts.add("begin");
ts.add("1");
ts.add("2");
ts.add("3");
ts.add("4");
ts.add("end");
for(Object o: ts)
    System.out.println(o);
System.out.println("\\n"+ts.first()); // 1  返回集合中第一个元素  返回最后元素:ts.last()
System.out.println(ts.subSet("a","b")); // [aaa, aaa0] 返回范围内部分元素
System.out.println(ts.tailSet("0")); // 返回大于或等于某元素的所有元素
System.out.println(ts.headSet("3")); // 返回小于某元素的所有元素

五、Queue 接口与实现类

  • Queue接口
    Queue 继承自 Collection 接口 ,Deque, LinkedList, PriorityQueue, BlockingQueue 等类都实现了它。队列通常但不一定是以FIFO(先进先出)方式排序元素。

  • Deque接口
    双向队列(Deque),是Queue的一个子接口,双向队列是指该队列两端的元素既能入队(offer)也能出队(poll).它的实现类:ArrayDeque。

  • PriorityQueue、ArrayDeque

1-- PriorityQueue继承AbstractQueue抽象类,抽象类继承AbstractCollection抽象类实现了Queue接口,优先队列不允许null元素,且非线程安全的。其容器是一个object的数组。默认情况下采用的是自然排序,取出的是队列最小的元素。

Collection c = Arrays.asList("a","b","c");
PriorityQueue<String> pq = new PriorityQueue<String>(c);
pq.offer("0"); // 指定的元素插入到此优先级队列
//pq.offer(null); // 不允许插入null
// pq.add(null); // 调用 offer方法插入元素
pq.offer("a"); // 允许重复的值
System.out.println(pq.remove("v"));// false 从该队列中删除指定元素的单个实例(如果存在)
System.out.println(pq.peek()); // 检索但不删除此队列的头,不存在则返回null
System.out.println(pq.poll()); // 检索并删除此队列的头,不存在则返回null
System.out.println(pq.size());
System.out.println(pq); // [a, a, c, b]
for(Object o : pq){
    System.out.println(o); // 遍历队列中的元素
}

2--ArrayDeque 继承了AbsrtactCollection抽象类,实现了Deque接口。所以ArrayDeque拥有两者的特性。由于是两端队列,所以其顺序是按照元素插入数组中对应位置产生的。

Collection c = Arrays.asList("a","b","c");
 ArrayDeque<String> aq = new ArrayDeque<String>(c);
 aq.addFirst("start"); // 头部插入指定元素 等同于offerFirst
 aq.addLast("end"); // 尾部插入指定元素 等同于offerLast
 //aq.add(null); // 不允许插入null
 aq.add("0"); // 末尾插入指定的元素, 调用addLast
 System.out.println(aq);
 System.out.println(aq.getFirst()); // start 检索但不删除,这个deque的第一个元素
 System.out.println(aq.getLast()); // 0 检索但不删除,这个deque的最后一个元素
 aq.offer("in"); // 调用 offerLast 再调用 addLast.实质与add一样。
 System.out.println(aq.pop()); // 删除第一个元素 调用 removeFirst 再调用 pollFirst
 System.out.println(aq.poll()); // 删除第一个元素 调用 pollFirst
 aq.push("me"); // 将元素推到第一个位置 调用 addFirst
 System.out.println(aq);

六、Collections 和 Arrays 工具类

Collections该工具类提供了大量方法对集合进行排序、查询和修改等操作,还提供了将集合对象置为不可变、对集合对象实现同步控制等方法。
Arrays 工具类提供了将数组转换为集合的方法 Arrays.asList().

List<String> l = Arrays.asList("a","b","c","d","e","f");
// 对列表中的元素进行翻转
Collections.reverse(l);
System.out.println(l); // [f, e, d, c, b, a]
//l.add("1"); 会抛出异常java.lang.UnsupportedOperationException,Arrays.asList()返回的是其内部类的 new ArrayList()对象
// 而其内部类没有重写 AbstractList中的add方法,所以调用的是父类的add,而父类的add方法直接抛出异常
List<String> nl = new ArrayList<>(l);
nl.add("0");
// 对列表默认顺序(自然顺序)进行排序
Collections.sort(nl);
System.out.println(nl); // [0, a, b, c, d, e, f]
nl.add("aa");
// 根据其元素的 自然顺序返回给定集合的最大\\小元素
System.out.println( Collections.max(l)); // f
System.out.println( Collections.min(l)); // a
System.out.println(nl); // [0, a, b, c, d, e, f, aa]
// 使用指定的随机源随机排列指定的列表
Collections.shuffle(nl, new Random()); // 不带种子的随机数,每次都不一样。反之,每次都一样
System.out.println(nl); // [b, aa, f, d, 0, c, a, e]
// 如果两个指定的集合没有共同的元素,则返回 true
System.out.println(Collections.disjoint(l, nl)); 

注:
http://www.trinea.cn/category/java/
http://www.cnblogs.com/midiyu/p/8145503.html
http://www.benchresources.net/java/collection-framework/
https://blog.csdn.net/u011240877/article/category/6447444
https://docs.oracle.com/javase/tutorial/collections/interfaces/collection.html

以上是关于Java_集合框架的主要内容,如果未能解决你的问题,请参考以下文章

Java_集合框架

Java_集合框架

集合00_Java集合框架

Java基础04_集合框架

Java 集合框架初步

比较 C# 中的字符串片段并从集合中删除项目