Java集合详解
Posted 海绵宝宝的菠萝屋*
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java集合详解相关的知识,希望对你有一定的参考价值。
java集合
集合、数组都是对多个数据进行存储操作的结构,简称Java容器。
说明:此时的存储,主要是指的内存层面的存储,不涉及到持久化的存储 。
数组在存储多个数据方面的缺点:
一旦初始化以后,其长度就不可以修改。
数组中提供的方法十分有限,对于添加,删除,插入数据等操作时非常不便,同时效率不高。
获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用。
数组存储数据的特点: 有序、可重复。对于无序、不可重复的需求,不能满足。
于是有了集合(相当于动态开辟内存空间的数组)
一,Collection集合接口
java.util.Collection是单值集合操作的最大的父接口,在该接口中定义了所有的单值数据的处理操作。这个图非常重要!!!!
二、List集合
List是Collection最常用的子接口,其最大的特点是允许保存重复元素的数据,并且List接口对Collection接口方法进行扩充
List扩充的三个方法
public E get(int index) 获取指定索引的数据
public E set(int index,E element) 修改指定的索引数据
public ListIterator<E> listIterator 返回listItertor接口
2.1 ArrayList
ArrayList子类是在使用List接口最常用的一个子类,该类利用数组实现List集合操作
复习旧的知识可以从源码中分析:(如果不会看源码没有关系 先学会看API)
通过有参构造方法发现,在ArrayList里面包含的数据实际上就是一个对象数组。
范例:集合操作的方法
public class LinkedList12
public static void main(String[] args)
List<String> all = new ArrayList<>();
System.out.println("集合是否为空?"+all.isEmpty()+"集合的元素个数:"+all.size());
all.add("一只羊");
all.add("一只羊"); //允许重复
all.add("两只羊");
System.out.println("数据存在判断:"+all.contains("一只羊"));
all.remove("两只羊");
System.out.println("集合是否为空?"+all.isEmpty()+"集合的元素个数:"+all.size());
System.out.println(all.get(1)); //获取指定索引元素
这个类本身含有的add()方法是如何实现东西添加的呢?
通过grow()这个方法我们可以发现,如果ArrayList集合里面保存的对象数组长度不够的时候会进行新的数组开辟,同时将原始的旧数组拷贝到新数组当中。
那新的大小是如何定义的呢?
JDK1.9之后:ArrayList默认的构造方法只会使用默认的空数组,使用的时候才会开辟新的数。
JDK1.9之前:ArrayList默认的构造会默认开辟大小为10的数组。
2.2、LinkedList
LinkedList子类是基于链表的形式实现的List接口标准。
先观察其继承关系:
LinkedList和ArrayList的使用是完全一样的,但是其内部的实现机制是完全不同的,首先观察LinkedList的构造方法。
其底层数据结构链表的实现。
面试题:请问ArrayList与LinkedList有什么区别?
ArrayList是数组实现的集合操作,而LinkedList是链表实现的集合操作。
链表与数组最大的区别在于:链表实现不需要频繁的进行新数组的空间开辟,
但是数组在根据索引获取数据时时间复杂度为O(1),链表的时间复杂度为O(n)。
(List集合中的get()方法)根据索引获取数据时,ArrayList的时间复杂度为O(1),LinkedList的时间复杂度为O(n)。
ArrayList在使用的时候默认的初始化对象数组的大小长度为10,如果空间不足采用2倍形式进行容量的扩充,如果保存大数据的时候有可能造成垃圾的产生以及性能的下降,但是这个时候可以使用LinkedList子类保存。
2.3 Vector
Vector是一个原始的程序类,这个类在JDK1.0时就提供,而到了JDK1.2的时候,很多开发者已经习惯使用Vector,而且许多系统类也是基于Vector来实现的。
关于Vector的进一步说明
ArrayList与Vector除了推出时间不同以外,实际上他们内部的实现机制也有所不同,通过源代码的分析可以发现Vector类的操作方法采用的都是synchronize同步处理,而ArrayList并没有进行同步处理,所有Vector类中方法在多线程访问的时候属于线程安全的,但是性能不如ArrayList高,所以在考虑到线程并发访问的情况下才会去使用Vector子类。
三,set集合
Set集合的定义如下:
Set接口中定义的方法是Set是无序(无下标),不重复的,当使用(jdk1.9才有这个方法,1.8没有)of() 这个新方法的时候如何发现集合中存在重复的元素则会直接抛出异常,Set集合的常规使用形式一定是依靠子类进行实例化的,Set接口中有两个常用的子类:
HashSet(散列存放) TreeSet(有序存放)
HashSet
HashSet是Set接口较为常见的子类,所有的内容都采用散列(无序)的方式进行存储。该子类的最大特点就是不允许保存重复元素,为啥呢?
HashSet会识别重复的元素,HashSet可以实现去重操作。
HashSet如何实现去重的呢?
它利用的是Object类中提供的方法实现的:
public int hashCode(); // 对象编码
public boolean equals(Object obj); // 对象比较
首先利用hashCode()进行编码匹配,如果编码不存在则表示数据不存在,证明没有重复的对象需要比较,如果发现重复了,则该数据是不能被保存。
TreeSet
TreeSet(内部实现二叉树) 特点:有序 不重复 主要作用:排序。
这个类需要根据Comparable接口来确定大小关系。
public static void main(String[] args)
Set<String> all = new TreeSet<>();
all.add("sky_ang");
all.add("Java");
all.add("Java");
all.add("Hello World");
System.out.println(all);
通过执行结果发现:所有保存的数据都会按照从小到大的顺序(字符串会按照字母大小的顺序依次比较)排列,并且元素不重复。
在Java程序之中,判断重复元素的判断处理就是hashCode()与equals()两个方法共同完成。
四,Map集合
在开发当中,Collection集合保存数据的目的是为了输出,Map集合保存数据的目的是为了进行key的查找。
Map接口是进行二元偶对象保存的最大父接口public interface Map<K,V>
通过HashMap实例化Map接口,可以针对key或value保存null的数据,同时发现及时保存数据的key重复,那么也不会出现错误。
但是对于Map接口提供的put()方法本身是有返回值的,这个返回值是指在重复key的情况下返回旧的value。
以下这个图非常重要!!!
HashMap
HashMap是Map接口中常用的子类,该类的主要特点是采用散列的方式存储。
范例:使用HashMap进行Map集合操作
public class HashMap12
public static void main(String[] args)
Map<String, Integer> map = new HashMap<String,Integer>();
map.put("one",1);
map.put("two",2);
map.put("one",12); //key重复会发生覆盖
map.put("zero",null);
map.put(null,1);
System.out.println(map.get("one"));
System.out.println(map.get(null));
System.out.println(map.get("ten"));
后面有两道面试题是关于HashMap的源码理解,请不要着急哦!
LinkedHashMap
Hash采用的是散列算法进行数据存储,这就造成了无序存放,但是要求严格下需要按照顺序存放,所以提供了链表的形式的Map集合。
LinkedHashMap子类最大的特点是可以基于链表形式实现偶对象的存储,这样就可以保证集合的存储顺序与数据增加的顺序相同
Hashtable
Hashtable是早期的字典实现类,可以方便的实现数据的查询
public static void main(String[] args)
Map<String, Integer> map = new Hashtable<String, Integer>();
map.put("one",1);
map.put("two",2);
System.out.println(map);
HashMap与Hashtable的区别
HashMap中的方法都属于异步操作(非线程安全),HashMap允许保存的数据为空,Hashtable中的方法都属于同步操作(线程安全),Hashtable不允许保存null数据,否则会出现NullPointException异常。
TreeMap
Map集合的主要功能是依据key实现数据的查询需求,为了方便进行key排序操作提供了TreeMap集合,
public static void main(String[] args)
Map<String, Integer> map = new TreeMap<String,Integer>();
map.put("c",1);
map.put("b",2);
map.put("a",3);
System.out.println(map);
本程序将TreeMap中保存的key类型设置为String,由于String实现了Comparable接口,所以此时可以根据保存的字符的编码由低到高进行排序。
面试题一:
HashMap是如何实现容量扩充的?
初始化容量扩充为16
当保存内容的容量扩充超过了与阈值*0.75=12时,就会进行容量的扩充。
在进行扩充的时候HashMap采用的成倍的扩充模式即:每一次扩充两倍(源码用的左移运算符1<<)
面试题二:HashMap的工作原理
在HashMap之中进行数据存储的依然是利用Node类完成的,那么这种情况就是可以使用的数据结构之后两种:链表和二叉树,本质区别在于时间复杂度不同,链表存储时间复杂度O(n),二叉树存储O(logn)(树的高度)
从jdk1.8开始,HashMap的实现出现了改变,因为其要适应大数据的海量数据存储,其存储发生了改变,并且HashMap内部中提供了一个特别重要的常量:
在使用HashMap存储数据的时候,如果保存的数据个数没有超过阈值8,那么会按照链表的方式存储;
则会将链表转为红黑树实现树的平衡,并且利用左旋与右旋来保证数据的查询性能。
扩展红黑树:
红黑树的特点:节点是红色或者黑色,
2,根节点是黑色的
3,每个叶子的节点都是黑色的空节点(NULL)
4,每个红色节点的两个节点都是黑色的
5,从任意节点 到 其每个叶子节点的 所有路径都包含相同的黑色节点(黑色高度相同)
插入和删除节点或导致红黑树不平衡,当红黑色不平衡时,有两种调整方式**【变色】和【旋转】**
五 集合输出(Iterator)
Collection接口提供toArray()的方法可以将集合保存的数据转为对象数据返回,用户可以利用数组的循环方法进行内容的获取,但是此类的方法由于性能不高不是集合输出的首选方案,集类集框架中对于集合的输出提供了四种方式:
Iterator,ListIterator,Enumeration,foreach
这里主要讲foreach输出,foreach除了支持数组的输出以外,也支持集合的输出。
范例1:使用foreach输出set集合数据
public class Foreach12
public static void main(String[] args)
Set<String> strings = new HashSet<String>();
strings.add("sky_ang");
strings.add("skyang.cn 这个是我的个人网站");
for (String temp : strings)
System.out.println(temp);
Java集合类详解
转载至:
Java集合类详解
Java的集合就像是一种容器,可以把对个对象的引用放入容器中,其中不断可以存储不等的多个对象,还可以用于保存具有映射关系的关联数组。其中Java的集合可以分为三种体系:
- Set集合:内部元素无序,并且元素不可以重复;
- List集合:内部元素有序,且元素可以重复;
- Map集合:具有映射关系的集合
(一)Collection接口:
Collection接口是List,Set和Queue接口的父接口,该接口中定义的方法可以用户操作List,Set和Queue集合;其中主要有以下的一些方法:
这里给出测试上述部分方法的举例:
首先给出Person类,用于放入集合中
1 package collection; 2 3 /** 4 * Created by : Zhong 5 * DATE : 2017/3/2 6 * Time : 23:06 7 * Funtion : 8 */ 9 public class Person { 10 public String name; 11 public int age; 12 13 14 public Person() { 15 16 } 17 18 public Person(String name, int age) { 19 this.name = name; 20 this.age = age; 21 } 22 23 24 public String getName() { 25 return name; 26 } 27 28 public void setName(String name) { 29 this.name = name; 30 } 31 32 33 public int getAge() { 34 return age; 35 } 36 37 public void setAge(int age) { 38 this.age = age; 39 } 40 41 @Override 42 public String toString() { 43 return "Person{" + 44 "name=‘" + name + ‘\\‘‘ + 45 ", age=" + age + 46 ‘}‘; 47 } 48 49 @Override 50 public boolean equals(Object o) { 51 if (this == o) return true; 52 if (o == null || getClass() != o.getClass()) return false; 53 54 Person person = (Person) o; 55 56 if (age != person.age) return false; 57 return name != null ? name.equals(person.name) : person.name == null; 58 59 } 60 61 @Override 62 public int hashCode() { 63 int result = name != null ? name.hashCode() : 0; 64 result = 31 * result + age; 65 return result; 66 } 67 }
然后举例说明Collection接口的相关方法:
1 package collection; 2 3 import org.junit.Test; 4 5 import java.util.ArrayList; 6 import java.util.Collection; 7 import java.util.Iterator; 8 9 /** 10 * Created by :Infaraway 11 * DATE : 2017/3/26 12 * Time : 12:35 13 * Funtion : 14 */ 15 public class CollectionTest { 16 17 18 19 @Test 20 public void testTool(){ 21 Collection collection = new ArrayList(); 22 Collection collection2 = new ArrayList(); 23 Person person = new Person("Tom", 22); 24 collection.add(person); 25 collection.add(new Person("Jerry", 25)); 26 collection.add(new Person("Mike", 32)); 27 collection.add("infaraway"); 28 29 //1. contains(Object obj):利用equals方法比较,查看集合中有没有指定元素 30 boolean flag = collection.contains(new Person("Mike", 32)); 31 System.out.println(flag); 32 flag = collection.contains(person); 33 System.out.println(flag); 34 35 //2. containsAll(Collection coll)利用equals方法比较,查看集合中有没有指定元素的集合 36 collection2.add(person); 37 collection2.add("infaraway"); 38 flag = collection.containsAll(collection2); 39 System.out.println(flag); 40 41 //3. isEmpty():检查集合是否为空 42 flag = collection.isEmpty(); 43 System.out.println(flag); 44 45 //4. toArray()转化集合为数组 46 Object [] object = collection.toArray(); 47 System.out.println(object.length); 48 49 //toArray(T[] a) 50 } 51 52 53 /** 54 * 1. clear() 清空集合 55 * 2. remove() :移除指定的元素,通过equals() 方法在集合中查找指定的元素 56 * 如果元素存在,则移除 57 * 3. removeAll(Collection coll) 移除coll中有的元素 58 * 4. retainAll(Collection coll) 保存coll中有的元素 59 */ 60 @Test 61 public void testRemove(){ 62 63 Collection collection = new ArrayList(); 64 Collection collection2 = new ArrayList(); 65 Person person = new Person("Tom", 22); 66 collection.add(person); 67 collection.add(new Person("Jerry", 25)); 68 collection.add(new Person("Mike", 32)); 69 collection.add("infaraway"); 70 71 /* System.out.println(collection.size()); 72 collection.remove(person);*/ 73 74 System.out.println(collection.size()); 75 76 collection2.add(person); 77 collection2.add("infaraway"); 78 79 collection.removeAll(collection2); 80 System.out.println(collection.size()); 81 } 82 83 /** 84 * 在Collection中无法获取指定的元素,但是可以遍历所有的元素 85 * 1. 使用增强for循环遍历 86 * 2. 使用Iterator迭代器遍历 87 * 2.1 获取迭代器对象,调用Collection的iterator方法,获取Iterator接口的实现 88 * 2.2 调用Iterator接口方法进行迭代 89 */ 90 @Test 91 public void testIterator(){ 92 93 Collection collection = new ArrayList(); 94 Collection collection2 = new ArrayList(); 95 collection.add("infaraway"); 96 97 Person person = new Person("Tom", 22); 98 collection.add(person); 99 collection.add(new Person("Jerry", 25)); 100 collection.add(new Person("Mike", 32)); 101 102 //使用addAll方法 103 collection2.addAll(collection); 104 105 /* System.out.println(collection.size()); 106 for (Object o : collection) { 107 System.out.println(o); 108 }*/ 109 110 Iterator it = collection2.iterator(); 111 while(it.hasNext()){ 112 System.out.println(it.next()); 113 } 114 115 116 } 117 118 /** 119 * add()方法 120 */ 121 @Test 122 public void testCollection(){ 123 Collection collection = new ArrayList(); 124 collection.add("infaraway"); 125 collection.add(new Person("Tom", 22)); 126 collection.add(new Person("Jerry", 25)); 127 collection.add(new Person("Mike", 32)); 128 } 129 130 }
(二)Set集合
Set集合不允许包含相同的元素,如果把两个相同的元素添加进入Set集合,则添加操作失败。Set集合中判断两个对象是否相同不是使用“==” 而是根据equals()方法的返回值决定;
2.1 HashSet
1)HashSet特点
HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。
HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。
HashSet 具有以下特点:
- 不能保证元素的排列顺序
- HashSet 不是线程安全的
- 集合元素可以使 null
当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。
重写 hashCode() 方法的基本原则
- 在程序运行时,同一个对象多次调用 hashCode() 方法应该返回相同的值
- 当两个对象的 equals() 方法比较返回 true 时,这两个对象的 hashCode() 方法的返回值也应相等
- 对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值
package collection; import org.junit.Test; import java.util.HashSet; import java.util.Set; /** * Created by :Infaraway * DATE : 2017/3/26 * Time : 13:18 * Funtion : 测试HashSet * * 关于HashSet * 1. HashSet是Set的最典型的实现 * 2. HashSet中不能有重复的元素,判断两个元素相等的标准是equals()方法返回true * 3. HashSet根据hashCode()值来存储元素,因此不能保证元素的顺序 * 4. 如果两个对象通过equals()方法返回true 这两个对象的hashcode值应该是相同的 * 5. HashSet 是线程不安全的 */ public class HashSetTest { @Test public void testAdd(){ Set set = new HashSet(); set.add(new Person("AAA",22)); set.add(new Person("BBB",22)); set.add(new Person("CCC",27)); set.add(new Person("DDD",29)); System.out.println(set.size()); for (Object person : set) { System.out.println(person.toString()); } } }
2)子类 LinkedHashSet
LinkedHashSet 集合根据元素的hashCode值来决定元素的存储位置,但它同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的。
LinkedHashSet 性能插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。
LinkedHashSet 不允许集合元素重复。
2.2 TreeSet
TreeSet 是 SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态。
其中TreeSet还有以下的一些常用的操作:这里就不一一列举实现了
- Comparator comparator()
- Object first() 获取第一个元素
- Object last() 获取最后一个元素
- Object lower(Object e)
- Object higher(Object e)
- SortedSet subSet(fromElement, toElement)
- SortedSet headSet(toElement)
- SortedSet tailSet(fromElement)
TreeSet 支持两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序。
1)自然排序
排序:TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序排列,如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现 Comparable 接口。实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即通过 compareTo(Object obj) 方法的返回值来比较大小。
实现Compareable接口代码示例:
1 package collection; 2 3 /** 4 * Created by : Zhong 5 * DATE : 2017/3/2 6 * Time : 23:06 7 * Funtion : 8 */ 9 public class PersonCompare implements Comparable{ 10 public String name; 11 public int age; 12 public PersonCompare() { 13 } 14 public PersonCompare(String name, int age) { 15 this.name = name; 16 this.age = age; 17 } 18 public String getName() { 19 return name; 20 } 21 public void setName(String name) { 22 this.name = name; 23 } 24 public int getAge() { 25 return age; 26 } 27 public void setAge(int age) { 28 this.age = age; 29 } 30 @Override 31 public String toString() { 32 return "Person{" + 33 "name=‘" + name + ‘\\‘‘ + 34 ", age=" + age + 35 ‘}‘; 36 } 37 38 @Override 39 public boolean equals(Object o) { 40 if (this == o) return true; 41 if (o == null || getClass() != o.getClass()) return false; 42 43 PersonCompare person = (PersonCompare) o; 44 45 if (age != person.age) return false; 46 return name != null ? name.equals(person.name) : person.name == null; 47 48 } 49 @Override 50 public int hashCode() { 51 int result = name != null ? name.hashCode() : 0; 52 result = 31 * result + age; 53 return result; 54 } 55 56 @Override 57 public int compareTo(Object o) { 58 59 if (o instanceof PersonCompare){ 60 PersonCompare personCompare = (PersonCompare) o; 61 return this.name.compareTo(personCompare.name); 62 }else{ 63 throw new ClassCastException("转换类型失败!"); 64 } 65 } 66 }
自然排序方法的使用示例:
/** * 自然排序情况 * * 默认情况下TreeSet要求集合中的元素必须实现Comparable接口 * Comparable接口中只有一个方法: * public int compareTo(T o) * 如果返回0 代表两个元素相等 * 如果返回正数,代表当前元素大 * 如果返回负数,代表当前元素小 * TreeSet 会调用每个元素的compareTo()方法去和集合中的每个已经有的元素比较,进而决定当前元素在集合中的位置 * */ @Test public void testTreeSet(){ TreeSet treeSet = new TreeSet(); treeSet.add(new PersonCompare("AAA",16)); treeSet.add(new PersonCompare("BBB",13)); treeSet.add(new PersonCompare("CCC",11)); treeSet.add(new PersonCompare("DDD",15)); for (Object o : treeSet) { System.out.println(o.toString()); } }
Comparable 的典型实现:
- BigDecimal、BigInteger 以及所有的数值型对应的包装类:按它们对应的数值大小进行比较
- Character:按字符的 UNICODE 值来进行比较
- Boolean:true 对应的包装类实例大于 false 对应的包装类实例
- String:按字符串中字符的 UNICODE 值进行比较
- Date、Time:后边的时间、日期比前面的时间、日期大
因为只有相同类的两个实例才会比较大小,所以向 TreeSet 中添加的应该是同一个类的对象。当需要把一个对象放入 TreeSet 中,重写该对象对应的 equals() 方法时,应保证该方法与 compareTo(Object obj) 方法有一致的结果:如果两个对象通过 equals() 方法比较返回 true,则通过 compareTo(Object obj) 方法比较应返回 0
2)定制排序
如果需要实现定制排序,则需要在创建 TreeSet 集合对象时,提供一个 Comparator 接口的实现类对象。由该 Comparator 对象负责集合元素的排序逻辑。定制排序的优点就是让需要排序的对象不需要实现Compareable接口,减少了耦合性,是程序更加简单。
定制排序方法代码示例:
/** * 定制排序 * */ @Test public void testTreeSet2(){ //创建comparator接口的实现类对象 Comparator comparator = new Comparator() { @Override public int compare(Object o1, Object o2) { if (o1 instanceof Person && o2 instanceof Person){ Person p1 = (Person)o1; Person p2 = (Person)o2; return p1.getAge() - p2.getAge(); } throw new ClassCastException("类型转换异常"); } }; //创建TreeSet对象,传入Comparator接口的实现类对象 TreeSet treeSet = new TreeSet(comparator); treeSet.add(new Person("AAA",16)); treeSet.add(new Person("BBB",13)); treeSet.add(new Person("CCC",11)); treeSet.add(new Person("DDD",15)); for (Object person : treeSet) { System.out.println(person.toString()); } }
(三)List集合
3.1 概述
- List 代表一个元素有序、且可重复的集合,集合中的每个元素都有其对应的顺序索引
- List 允许使用重复元素,可以通过索引来访问指定位置的集合元素。
- List 默认按元素的添加顺序设置元素的索引。
- List 集合里添加了一些根据索引来操作集合元素的方法
- void add(int index, Object ele) 把元素添加到指定的位置 原来的元素被后移
- boolean addAll(int index, Collection eles) 把一组元素添加到指定的位置
- Object get(int index) 获取指定索引的元素
- int indexOf(Object obj) 获取指定对象的索引,如果元素不存在,则返回-1
- int lastIndexOf(Object obj) 获取重复的元素的最后一个索引
- Object remove(int index) 移除指定索引的元素
- Object set(int index, Object ele) 设置指定索引的元素,原来的元素被替换
- List subList(int fromIndex, int toIndex)
3.2 ArrayList 和 Vector
ArrayList 和 Vector 是 List 接口的两个典型实现
区别:
- 是一个古老的集合,通常建议使用 ArrayList
- ArrayList 是线程不安全的,而 Vector 是线程安全的。
- 即使为保证 List 集合线程安全,也不推荐使用 Vector
Arrays.asList(…) 方法返回的 List 集合即不是 ArrayList 实例,也不是 Vector 实例。 Arrays.asList(…) 返回值是一个固定长度的 List 集合。
(四)Map集合
4.1 概述
- Map 用于保存具有映射关系的数据,因此 Map 集合里保存着两组值,一组值用于保存 Map 里的 Key,另外一组用于保存 Map 里的 Value
- Map 中的 key 和 value 都可以是任何引用类型的数据
- Map 中的 Key 不允许重复,即同一个 Map 对象的任何两个 Key 通过 equals 方法比较中返回 false
- Key 和 Value 之间存在单向一对一关系,即通过指定的 Key 总能找到唯一的,确定的 Value。
常用方法:
- void clear() 清空map
- boolean containsKey(Object key) 检测是否包含key值
- boolean containsValue(Object value) 检测是否包含value值
- Set<Mao.Entry<K,V>> entrySet() 得到剪枝对对应的Entry 的Set
- V get(Object key)
- Set<K> keySet()
- V put(K key, V value)
- V remove(Object key) 移除指定key 的键值对
4.2 HashMap 和 Hashtable
- HashMap 和 Hashtable 是 Map 接口的两个典型实现类
- 区别:
- Hashtable 是一个古老的 Map 实现类,不建议使用
- Hashtable 是一个线程安全的 Map 实现,但 HashMap 是线程不安全的。
- Hashtable 不允许使用 null 作为 key 和 value,而 HashMap 可以
- 与 HashSet 集合不能保证元素的顺序的顺序一样,Hashtable 、HashMap 也不能保证其中 key-value 对的顺序
- Hashtable 、HashMap 判断两个 Key 相等的标准是:两个 Key 通过 equals 方法返回 true,hashCode 值也相等。
- Hashtable 、HashMap 判断两个 Value相等的标准是:两个 Value 通过 equals 方法返回 true
4.3 LinkedHashMap
LinkedHashMap 是 HashMap 的子类
LinkedHashMap 可以维护 Map 的迭代顺序:迭代顺序与 Key-Value 对的插入顺序一致
1 @Test 2 public void testLinkedHashMap(){ 3 Map map = new LinkedHashMap<>(); 4 5 map.put("CC", new Person("CC", 18)); 6 map.put("AA", new Person("AA", 10)); 7 map.put("DD", new Person("DD", 12)); 8 map.put("BB", new Person("BB", 16)); 9 10 /*Iterator it = map.keySet().iterator(); 11 while (it.hasNext()){ 12 Object key = it.next(); 13 Object value = map.get(key); 14 System.out.println(key+":"+value); 15 } 16 System.out.println();*/ 17 18 for (Object key : map.keySet()){ 19 Object value = map.get(key); 20 System.out.println(key+":"+value); 21 } 22 }
4.4 TreeMap
TreeMap 存储 Key-Value 对时,需要根据 Key 对 key-value 对进行排序。TreeMap 可以保证所有的 Key-Value 对处于有序状态。
TreeMap 的 Key 的排序:
- 自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException
- 定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口
同样这里的key值也需要具有可比性
1 @Test 2 public void testTreeMap(){ 3 Map map = new TreeMap<>(); 4 5 //这里使用加入Compareable接口的Person类,这样才可以进行排序 6 map.put(new PersonCompare("CC", 18),"CC"); 7 map.put(new PersonCompare("AA", 10),"AA"); 8 map.put(new PersonCompare("DD", 12),"DD"); 9 map.put(new PersonCompare("BB", 16),"BB"); 10 11 for (Object key : map.keySet()){ 12 Object value = map.get(key); 13 System.out.println(key+":"+value); 14 } 15 }
(五)操作集合的工具类:Collections
Collections 是一个操作 Set、List 和 Map 等集合的工具类
Collections 中提供了大量方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法
5.1 排序操作:
- reverse(List):反转 List 中元素的顺序
- shuffle(List):对 List 集合元素进行随机排序
- sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
- sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
- swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
5.2 查找、替换
- Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
- Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
- Object min(Collection)
- Object min(Collection,Comparator)
- int frequency(Collection,Object):返回指定集合中指定元素的出现次数
- boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值
5.3 同步控制
Collections 类中提供了多个 synchronizedXxx()方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题
代码示例:
1 package collection; 2 3 import org.junit.Test; 4 5 import java.util.*; 6 7 /** 8 * Created by :Infaraway 9 * DATE : 2017/3/26 10 * Time : 16:39 11 * Funtion : 12 */ 13 public class CollectionsTest { 14 15 @Test 16 public void testList(){ 17 List list = new ArrayList<>(); 18 list.add(new Person("AAA",16)); 19 list.add(new Person("BBB",13)); 20 list.add(new Person("CCC",11)); 21 list.add(new Person("DDD",15)); 22 23 for (Object o : list) { 24 System.out.println(o.toString()); 25 } 26 //按年龄升序排列 27 //实现Comparator类进行排序操作 28 Collections.sort(list, new Comparator() { 29 @Override 30 public int compare(Object o1, Object o2) { 31 if (o1 instanceof Person && o2 instanceof Person){ 32 Person p1 = (Person)o1; 33 Person p2 = (Person)o2; 34 return p1.getAge() - p2.getAge(); 35 } 36 throw new ClassCastException("类型转换异常"); 37 } 38 }); 39 40 System.out.println(); 41 for (Object o : list) { 42 System.out.println(o.toString()); 43 } 44 45 46 //获取list中最小的元素 47 //要求集合中的元素都实现Compareable接口 48 Set set = new HashSet(); 49 50 set.add(new PersonCompare("AAA",20)); 51 set.add(new PersonCompare("BBB",34)); 52 set.add(new PersonCompare("CCC",27)); 53 set.add(new PersonCompare("DDD",29)); 54 55 for (Object person : set) { 56 System.out.println(person.toString()); 57 } 58 System.out.println(); 59 60 Object object = Collections.min(set); 61 System.out.println(object.toString()); 62 } 63 64 }
本文所涉及的代码可以在这里找到: https://git.oschina.net/infaraway/basisJava/tree/master/src/collection
以上是关于Java集合详解的主要内容,如果未能解决你的问题,请参考以下文章