特点:1. 集合类也叫做容器类,和数组一样,用于存储数据,但数组类型单一,并且长度固定,限制性很大,而集合类可以动态增加长度;
2. 集合存储的元素都是对象(引用地址),所以集合可以存储不同的数据类型,但如果是需要比较元素来排序的集合,则需要类型一致;
3. 集合中提供了统一的增删改查方法,使用方便;
4. 支持泛型,避免数据不一致和转换异常,还对常用的数据结构进行了封装。
结构:集合框架体系是由Collection、Map(映射关系)和Iterator(迭代器)组成,下面只说常用,并非全部
注1:Map里面的键值对虽然没强调是否可重复,但是记住,Key是唯一的,但是Value可以重复,所以存在一个Value对应多个Key的状况;
1 public class Test { 2 public static void main(String[] args) { 3 // HashMap在初始化时,尽量确定大小,符合规范 4 HashMap<Integer, String> map = new HashMap<Integer, String>(16); 5 map.put(1, "张三"); 6 map.put(2, "张三"); 7 map.put(3, "李四"); 8 } 9 }
一、Collection架构源码观察及应用
1. 在Collection的结构中,声明了一些通用的方法,下面介绍常用的:
1 * boolean add(E e)-------------------->添加指定元素 2 * boolean addAll(Collection c)---------------->将指定集合中所有元素都添加到此 collection 3 * boolean contains(Object o)-------------------->集合中是否包含了指定元素 4 * boolean containsAll(Collection<?> c)------------>该集合是否包含指定集合中所有元素 5 * boolean remove(Object o)--------------------------->移除指定元素 6 * boolean removeAll(Collection<?> c)-------------->移除指定的collection参数的所有元素 7 * void clear()----------------------------------->清除集合中所有元素 8 * boolean retainAll(Collection<?> c)-------------------->保留指定Collection参数中元素,是两个集合的元素交集 9 * boolean equals(Object o)-------------------->比较此 collection 与指定对象是否相等 10 * boolean isEmpty()-------------------->判断该集合是否为空 11 * Iterator<E> iterator()-------------------->返回此 collection 的迭代器,用来遍历元素 12 * int hashCode()-------------------->返回集合的哈希码值 13 * int size()-------------------->返回此 collection 中的元素数 14 * Object[] toArray()-------------------->返回一个包含该Collection所有元素的对象数组 15 * <T> T[] toArray(T[] a)-------------------->返回一个包含该Collection所有元素的数组,数组类型和指定数组的类型一致
2. 声明方式:
Set类:
1 public static void main(String[] args) { 2 3 /** 4 * Set类: 5 * 不允许重复对象 6 * 无序容器,你无法保证每个元素的存储顺序,TreeSet通过Comparator或者 Comparable维护了一个排序顺序。 7 * 只允许一个 null 元素 8 * Set接口最流行的几个实现类是HashSet、LinkedHashSet以及TreeSet。最流行的是基于HashMap实现的HashSet; 9 * TreeSet还实现了SortedSet接口,因此TreeSet 是一个根据其compare()和compareTo()的定义进行排序的有序容器。 10 */ 11 HashSet<String> hashSet = new HashSet<String>(); 12 LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>(); 13 TreeSet<String> treeSet = new TreeSet<String>(); 14 15 // 另一种写法, 不过推荐第一种写法,他两本质差不多 16 Set<String> hashSet1 = new HashSet<String>(); 17 Set<String> linkedHashSet1 = new LinkedHashSet<String>(); 18 Set<String> treeSet1 = new TreeSet<String>(); 19 20 // 验证TreeSet的有序性 21 for (int i = 0; i < 100; i++) { 22 hashSet.add(""+i); 23 } 24 System.out.println(hashSet); 25 // 输出: [88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 10, 98, 11, 99, 12... 26 treeSet.addAll(hashSet); 27 System.out.println(treeSet); 28 // 输出: [0, 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 20, 21, 22, 23, 24, 25, 26... 29 }
List类:
1 public static void main(String[] args) { 2 /** 3 * Arraylist: 4 * 优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。 5 * 缺点:因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。 6 * 7 * LinkedList: 8 * 优点:LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址, 9 * 对于新增和删除操作add和remove,LinedList比较占优势。LinkedList 适用于要头尾操作或插入指定位置的场景 10 * 缺点:因为LinkedList要移动指针,所以查询操作性能比较低。 11 */ 12 ArrayList<Integer> arrayList = new ArrayList<Integer>(); 13 LinkedList<Integer> linkedList = new LinkedList<Integer>(); 14 }
3. 方法的简单运用
1 public static void main(String[] args) { 2 3 4 /** 5 * boolean add(E e)-------------------->添加指定元素 6 * boolean addAll(Collection c)---------------->将指定集合中所有元素都添加到此 collection 7 * boolean contains(Object o)-------------------->集合中是否包含了指定元素 8 * boolean containsAll(Collection<?> c)------------>该集合是否包含指定集合中所有元素 9 * boolean remove(Object o)--------------------------->移除指定元素 10 * boolean removeAll(Collection<?> c)-------------->移除指定的collection参数的所有元素 11 * void clear()----------------------------------->清除集合中所有元素 12 * boolean retainAll(Collection<?> c)-------------------->保留指定Collection参数中元素,是两个集合的元素交集 13 * boolean equals(Object o)-------------------->比较此 collection 与指定对象是否相等 14 * boolean isEmpty()-------------------->判断该集合是否为空 15 * Iterator<E> iterator()-------------------->返回此 collection 的迭代器,用来遍历元素 16 * int hashCode()-------------------->返回集合的哈希码值 17 * int size()-------------------->返回此 collection 中的元素数 18 * Object[] toArray()-------------------->返回一个包含该Collection所有元素的对象数组 19 * <T> T[] toArray(T[] a)-------------------->返回一个包含该Collection所有元素的数组,数组类型和指定数组的类型一致 20 */ 21 22 23 HashSet<String> hashSet = new HashSet<String>(); 24 for (int i = 0; i < 100; i++) { 25 hashSet.add(""+i); 26 } 27 System.out.println("hashSet:" + hashSet); 28 //输出:[88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 10, 98, 11, 99, 12...,可以看见HashSet的无序的 29 30 System.out.println("hashSet.size(): "+hashSet.size()); 31 System.out.println("hashSet.hashCode(): "+hashSet.hashCode()); 32 // 输出: hashSet.hashCode(): 153120 33 34 HashSet<String> hashSet1 = new HashSet<String>(); 35 hashSet1.addAll(hashSet); 36 System.out.println("hashSet1.addAll(hashSet): " + hashSet1); 37 38 System.out.println("hashSet.equals(hashSet1): "+hashSet.equals(hashSet1)); 39 40 hashSet1.removeAll(hashSet); 41 System.out.println("hashSet1.removeAll(hashSet): " + hashSet1); 42 43 hashSet.clear(); 44 System.out.println("hashSet.clear(): " + hashSet); 45 46 System.out.println("hashSet.isEmpty(): "+hashSet.isEmpty()); 47 } 48 /** 49 * 结果: 50 * hashSet:[88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 10, 98, 11, 99, 12, 13, 14, 15,... 51 * hashSet.size(): 100 52 * hashSet.hashCode(): 153120 53 * hashSet1.addAll(hashSet): [88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 10, 98, 11,, ... 54 * hashSet.equals(hashSet1): true 55 * hashSet1.removeAll(hashSet): [] 56 * hashSet.clear(): [] 57 * hashSet.isEmpty(): true 58 */
二、Map架构源码观察及应用
1. 声明方式及其使用环境
1 public static void main(String[] args) { 2 3 /** 4 * HashMap非线程安全,基于哈希表实现。使用HashMap要求添加的键类明确定义了hashCode()和equals()[可以重写hashCode()和equals()], 5 * 为了优化HashMap空间的使用,您可以调优初始容量和负载因子。 6 * TreeMap非线程安全,基于红黑树实现。TreeMap没有调优选项,因为该树总处于平衡状态。 7 * 8 * 适用场景分析: 9 * 1)、HashMap和HashTable区别 10 * HashMap去掉了HashTable的contains方法,但是加上了containsValue()和containsKey()方法。 11 * HashTable是同步的,而HashMap是非同步的,效率上比HashTable要高。 12 * HashMap允许空键值,而HashTable不允许。 13 * 14 * 2)、HashMap和Treemap区别 15 * HashMap适用于Map中插入、删除和定位元素。 16 * Treemap:适用于按自然顺序或自定义顺序遍历键(key)。 17 */ 18 HashMap<Integer, String> hashMap = new HashMap<Integer, String>(16); 19 TreeMap<String, String> treeMap = new TreeMap<String, String>(); 20 LinkedHashMap<Integer, String> linkedHashMap = new LinkedHashMap<Integer, String>(); 21 }
2. 常用方法及其简单应用
1 public static void main(String[] args) { 2 /** 3 * boolean containsKey(Object key)----------------->该映射是否包含指定键值 4 * boolean containsValue(Object value)----------------->如果该键值对中有一个或多个key射到指定值,则返回 true 5 * Set<Map.Entry<K,V>> entrySet()----------------->返回此映射中包含的映射关系的 Set 视图。 6 * Set<K> keySet()----------------->返回此映射中所有键的 Set 视图。 7 * Collection<V> values()----------------->返回一个此映射中包含的值的 Collection 8 * V get(Object key)----------------->返回指定键映射的值。如果不存在,则返回 null 9 * V put(K key, V value)----------------->放入一个键值对(key-value) 10 * void putAll(Map<? extends K,? extends V> m)----------------->把指定映射的所有映射关系复制到此映射中 11 * boolean isEmpty()----------------->如果此映射未包含键值映射关系,则返回 true 12 * boolean equals(Object o)----------------->比较指定的对象与此映射是否相等 13 * int size()----------------->返回此映射中的键-值映射关系数 14 * int hashCode()----------------->返回此映射的哈希码值 15 */ 16 17 HashMap<Integer, String> hashMap = new HashMap<Integer, String>(16); 18 TreeMap<Integer, String> treeMap = new TreeMap<Integer, String>(); 19 LinkedHashMap<Integer, String> linkedHashMap = new LinkedHashMap<Integer, String>(); 20 21 for (int i = 1; i <= 10; i++) { 22 hashMap.put(i, "第" + i + "个键对应的值"); 23 } 24 25 //第一种:普遍使用,二次取值 26 System.out.println("通过Map.keySet遍历key和value:"); 27 for (Integer key : hashMap.keySet()) { 28 System.out.println("key= "+ key + " and value= " + hashMap.get(key)); 29 } 30 31 //第二种 32 System.out.println("通过Map.entrySet使用iterator遍历key和value:"); 33 Iterator<Map.Entry<Integer, String>> it = hashMap.entrySet().iterator(); 34 while (it.hasNext()) { 35 Map.Entry<Integer, String> entry = it.next(); 36 System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue()); 37 } 38 39 //第三种:推荐,尤其是容量大时</span> 40 System.out.println("通过Map.entrySet遍历key和value"); 41 for (Map.Entry<Integer, String> entry : hashMap.entrySet()) { 42 System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue()); 43 } 44 45 //第四种 46 System.out.println("通过Map.values()遍历所有的value,但不能遍历key"); 47 for (String v : hashMap.values()) { 48 System.out.println("value= " + v); 49 } 50 51 System.out.println(hashMap.containsKey(1)); // true 52 System.out.println(hashMap.containsValue("第1个键对应的值")); // true 53 System.out.println(hashMap.get(1)); // 第1个键对应的值 54 55 HashMap<Integer, String> hashMap1 = new HashMap<Integer, String>(); 56 hashMap1.putAll(hashMap); 57 System.out.println(hashMap.equals(hashMap1)); // true 58 59 treeMap.putAll(hashMap); 60 61 for (Map.Entry<Integer, String> entry : treeMap.entrySet()) { 62 System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue()); 63 } 64 65 System.out.println(treeMap.isEmpty()); // false 66 System.out.println(treeMap.size()); 67 }
注2 :
/**
* 什么场景下使用list,set,map呢?
* 1. 如果你经常会使用索引来对容器中的元素进行访问,那么List是你的正确的选择。如果你已经知道索引了的话,
* 那么List的实现类比如ArrayList可以提供更快速的访问,如果经常添加删除元素的,那么肯定要选择LinkedList。
*
* 2. 如果你想容器中的元素能够按照它们插入的次序进行有序存储,那么还是List,因为List是一个有序容器,它按照插入顺序进行存储。
*
* 3. 如果你想保证插入元素的唯一性,也就是你不想有重复值的出现,那么可以选择一个Set的实现类,
* 比如 HashSet、LinkedHashSet或者TreeSet。所有Set的实现类都遵循了统一约束比如唯一性,而且还提供了额外的特性:
* 比如TreeSet还是一个SortedSet,所有存储于TreeSet中的元素可以使用Java里的Comparator或者Comparable进行排序。
* LinkedHashSet也按照元素的插入顺序对它们进行存储。
*
* 4. 如果你以键和值的形式进行数据存储那么 Map 是你正确的选择。你可以根据你的后续需要从 Hashtable、HashMap、TreeMap 中进行选择。
*/