java集合类主要有Collection 和Map两个接口派生而出:
Collection体系继承树:
Map体系继承树:
一 集合中的常用方法:
1.数组长度使用.size();
2.增加数组的元素.add(1," ");
.add(" ");
两种方法的区别
3.修改某个元素的方法.set(1,"B");
4.删除元素的 方法.remove(2," ");
.remove(" ");
两种方法的区别
5.遍历数组的方法采用for方法
1. for(String s:all){
System.out.print(s+" ");
}
2. for(int i=0;i<all.size();i++){
System.out.println(all.get(i)+"");
}
二 List集合
1 list集合代表一个元素有序,可重复的集合,集合中的每个元素都有对应的顺序索引,访问list集合可以根据元素的索引来访问。
List判断两个对象相等只要通过equals方法()比较返回true即可.
2 ArrayList 和Vector
ArrayList 和Vector都是基于数组实现的List类,ArrayList 和Vector底层都封装了一个动态的 允许在分配的object数组。
ArrayList: 单线程效率高,也可以实现线程安全。
Vector : 多线程安全的,所以效率低
工具类:Arrays提供了asList()方法可以将一个数组或者指定对象的转化成一个集合。
3 Queue集合
queue集合模拟队列数据结构(先进先出)
PriorityQueue实现类:一个比较标准的队列实现,遍历 按照元素的大小重新排序。
Deque接口:是queue的子接口,代表一个双端队列
ArrayDeque:基于数组实现的双端队列。
4 LinkList实现类
底层使用的是使用双向链表的形式,存储的数据在空间上很可能不相邻,但是他们都有一个引用连在一起,所以增删起来会很方便,实现了list接口和Qeque接口,可以被当做一个双端队列。
ArrayList 和LinkList的区别:
ArrayList 是基于索引的数据接口,它的底层是数组。它可以以0(1)时间复杂度对元素进行随机访问。LinkedList 是以元素链表的形式存储它的数据,每一个元素都和它的前一个和后一个元素链接在一起,在这种情况下,查找某个元素的时间复杂度是0(n)。
相对于LinkedList,ArrayList 的插入,添加,删除操作速度慢一些,因为当元素被添加到集合任意位置的时候,需要像数组那样重新计算大小或者是更新索引。
LinkedLlist 比ArrayList 更占内存,因为LinkedList 为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。
三 Set集合
set集合无序集合元素不可重复。
1 HashSet
元素无序;
不同步;
当程序把度对象添加到hashSet中之后,尽量不要修改该集合中参与计算的hashcode()和equals()方法。
2 hashCode和equal()方法:
hashCode()方法和equal()方法的作用其实一样,重写的equal()里一般比较的比较全面比较复杂,这样效率就比较低,而利用hashCode()进行对比,效率很高,
但hashCode()并不是完全可靠,有时候不同的对象他们生成的hashcode也会一样(生成hash值得公式可能存在的问题),所以hashCode()只能说是大部分时候可靠,并不是绝对可靠,所以我们可以得出:
1.equal()相等的两个对象他们的hashCode()肯定相等,也就是用equal()对比是绝对可靠的。
2.hashCode()相等的两个对象他们的equal()不一定相等,也就是hashCode()不是绝对可靠的。
所有对于需要大量并且快速的对比的话如果都用equal()去做显然效率太低,所以解决方式是,每当需要对比的时候,首先用hashCode()去对比,如果hashCode()不一样,则表示这两个对象肯定不相等(也就是不必再用equal()去再对比了),如果hashCode()相同,此时再对比他们的equal(),如果equal()也相同,则表示这两个对象是真的相同了,这样既能大大提高了效率也保证了对比的绝对正确性!
这种大量的并且快速的对象对比一般使用的hash容器中,比如hashset,hashmap,hashtable等等,比如hashset里要求对象不能重复则他内部必然要对添加进去的每个对象进行对比,而他的对比规则就是像上面说的那样,先hashCode(),如果hashCode()相同,再用equal()验证,如果hashCode()都不同,则肯定不同,这样对比的效率就很高了。
然而hashCode()和equal()一样都是基本类Object里的方法,而和equal()一样,Object里hashCode()里面只是返回当前对象的地址,如果是这样的话,那么我们相同的一个类,new两个对象,由于他们在内存里的地址不同,则他们的hashCode()不同,所以这显然不是我们想要的,所以我们必须重写我们类的hashCode()方法,即一个类,在hashCode()里面返回唯一的一个hash值,比如下面:
自定义一个类
class Person{
int num;
String name;
public int hashCode(){
return num*name.hashCode();
}
}
由于标识这个类的是他的内部的变量num和name,所以我们就根据他们返回一个hash值,作为这个类的唯一hash值。
所以如果我们的对象要想放进hashSet,并且发挥hashSet的特性(即不包含一样的对象),则我们就要重写我们类的hashCode()和
equal()方法了。像String,Integer等这种类内部都已经重写了这两个方法。
当然如果我们只是平时想对比两个对象 是否一致,则只重写一个equal(),然后利用equal()去对比也行的。
3 LinkedHashSet
LinkedHashSet是Hashset的子类。根据元素的HashCode值来决定元素的存储位置,使用链表维护元素的次序,元素有序,性能低于hashSet;
4 SortedSet和TreeSet
TreeSet 是SortedSet的接口的实现类。
根据元素的大小来排序。
自然排序:
定制排序:
5 EnumSet
一个专为枚举设计的集合类,在内部已位向量的形式存储,(紧促,高效),对象占用内存小,运行效率高,在批量操作时,执行速度快。
四 Map集合
1概述
Map集合用于保存具有映射关系的数据,Map中保存着两组值,(Key,Value)
map集合中常用的方法:
1、添加:
1、V put(K key, V value) (可以相同的key值,但是添加的value值会覆
盖前面的,返回值是前一个,如果没有就返回null)
2、putAll(Map<? extends K,? extends V> m) 从指定映射中将所有映射关
系复制到此映射中(可选操作)。
2、删除
1、remove() 删除关联对象,指定key对象
2、clear() 清空集合对象
3、获取
1:value get(key); 可以用于判断键是否存在的情况。当指定的键不存在的时候,返
回的是null。
3、判断:
1、boolean isEmpty() 长度为0返回true否则false
2、boolean containsKey(Object key) 判断集合中是否包含指定的key
3、boolean containsValue(Object value) 判断集合中是否包含指定的value
4、长度:
Int size()
遍历Map的方式:
1、将map 集合中所有的键取出存入set集合。
Set<K> keySet() 返回所有的key对象的Set集合,再通过get方法获取键对应的值。
2、 values() ,获取所有的值.
Collection<V> values()不能获取到key对象
3、 Map.Entry对象 推荐使用 重点
Set<Map.Entry<k,v>> entrySet() 将map 集合中的键值映射关系打包成一个对象。
Map.Entry对象通过Map.Entry 对象的getKey,getValue获取其键和值。
2 HashMap和HashTable
HashMap 线程不安全,性能高,允许一个Key为null,和多个value为null.
HashTable:线程安全,性能低,不允许使用null作为key和value.
HashMap的工作原理:
HashMap基于hash原理,通过put()和get()方法存储和获取 对象,当我们将键值对传给put()方法时它调用键对象的hashCode()方法来计算hashCode,
3 LinkHashMap
LinkedHashMap是Hashmap的子类。根据元素的HashCode值来决定元素的存储位置,使用链表维护元素的次序,元素有序,性能低于hashMap;
4 Properties
是HashTable的子类,处理文件方便。
5 SortedMap接口和TreeMap接口
正如SortedSet接口右TreeSet实现类,Map接口也有SortedMap子类。SortedMap接口也有TreeMap实现类。
TreeMap就是一个红黑树数据结构,每个Key—Values作为红黑树的结点,存储时需要对结点进行排序。TreeMap可以保证所有的结点处于有序状态。有两种排序方式:
1 自然排序
2 定制排序
6 WeakHashMap
与HashMap的用法基本相似。 与HashMap的区别在于HashMap中的Key保留了对实际对象的强引用,意味着只要HashMap对象不被销毁,HashMap所有的Key引用的对象就不会被垃圾回收。HashMap也不会自动删除这些Key所对应的Key-Values对。
但WeakHashMap的Key只保留了对实际对象的弱引用,如果WeakHashMap的Key引用的对象没有被其他强引用变量所引用,Key所引用的对象可能会被垃圾回收。WeakHashMap就会自动删除K-V对。
7 EnumMap
一个与枚举类一起使用的Map实现,EnumMap中的Key必须是单个枚举类的枚举值。
五 迭代器
1、Iterator的API
关于Iterator主要有三个方法:hasNext()、next()、remove()
hasNext:没有指针下移操作,只是判断是否存在下一个元素
next:指针下移,返回该指针所指向的元素
remove:删除当前指针所指向的元素,一般和next方法一起用,这时候的作用就是删除next方法返回的元素
2、迭代器原理
1、当创建完成指向某个集合或者容器的Iterator对象是,这是的指针其实指向的是第一个元素的上方,即指向一个 空
2、当调用hasNext方法的时候,只是判断下一个元素的有无,并不移动指针
3、当调用next方法的时候,向下移动指针,并且返回指针指向的元素,如果指针指向的内存中没有元素,会报异 常。
4、remove方法删除的元素是指针指向的元素。如果当前指针指向的内存中没有元素,那么会抛出异常。
3、迭代器的用途
迭代器一般会用在遍历集合上面。
4、使用中注意的问题
Java中的Iterator是一种fail-fast的设计。
当Iterator迭代一个容器的时候,如果此时有别的方法在更改Collection(容器)的内容,那么Iterator就会抛出
ConcurrentModificationException 。正如官方文档中反复强调的:
Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic
behavior at an undetermined time in the future.
为了避免此Exception的发生,可以采取的解决方法是:
1.如果当前单个线程在更改容器(add, delete....),那么迭代的时候采用iterator.remove()方法可以确保迭代器在查找next的时候,指针不会丢失。
while(iterator.hasNext() {
Object item = iterator.next();
iterator.remove(); //Important! 避免ConcurrentModificationException
......
}
2.如果当前有多个线程在对容器进行操作,例如一个线程正在向容器中写数据,而另一个线程在迭代此容器,这时候就必须考虑并发下的线程安全问题。ConcurrentModificationException官方文档第一句就指出:
This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.
这时候可以采用java.util.concurrent包下面的线程安全的容器解决此异常。
最后要说的是,ConcurrentModificationException应该永远被用于解决一个bug,而不是检查程序的正确性(try...catch...)。
六 操作集合的工具类
1排序
1) 排序(Sort)使用sort方法可以根据元素的自然顺序 对指定列表按升序进行排序。列表中的所有元素都必须实现 Comparable接口。此列表内的所有元素都必须是使用指定比较器可相互比较的
double array[] = {112, 111, 23, 456, 231 };
for (int i = 0; i < array.length; i++) {
list.add(new Double(array[i]));
}
Collections.sort(list);
for (int i = 0; i < array.length; i++) {
System.out.println(li.get(i));
}
//结果:112,111,23,456,231
2) 混排(Shuffling)
混排算法所做的正好与 sort 相反: 它打乱在一个 List 中可能有的任何排列的踪迹。也就是说,基于随机源的输入重排该 List,这样的排列具有相同的可能性(假设随机源是公正的)。这个算法在实现一个碰运气的游戏中是非常有用的。例如,它可被用来混排代表一副牌的Card 对象的一个 List 。另外,在生成测试案例时,它也是十分有用的。
Collections.Shuffling(list)
double array[] = {112, 111, 23, 456, 231 };
for (int i = 0; i < array.length; i++) {
list.add(new Double(array[i]));
}
Collections.shuffle(list);
for (int i = 0; i < array.length; i++) {
System.out.println(li.get(i));
}
//结果:112,111,23,456,231
3) 反转(Reverse)
使用Reverse方法可以根据元素的自然顺序 对指定列表按降序进行排序。
Collections.reverse(list)
double array[] = {112, 111, 23, 456, 231 };
for (int i = 0; i < array.length; i++) {
list.add(new Double(array[i]));
}
Collections. reverse (list);
for (int i = 0; i < array.length; i++) {
System.out.println(li.get(i));
}
//结果:231,456,23,111,112
4) 替换所以的元素(Fill)
使用指定元素替换指定列表中的所有元素。
String str[] = {"dd","aa","bb","cc","ee"};
for(int j=0;j<str.length;j++){
li.add(new String(str[j]));
}
Collections.fill(li,"aaa");
for (int i = 0; i < li.size(); i++) {
System.out.println("list[" + i + "]=" + li.get(i));
}
//结果:aaa,aaa,aaa,aaa,aaa
5) 拷贝(Copy)
用两个参数,一个目标 List 和一个源 List, 将源的元素拷贝到目标,并覆盖它的内容。目标 List至少与源一样长。如果它更长,则在目标 List 中的剩余元素不受影响。
Collections.copy(list,li): 后面一个参数是目标列表 ,前一个是源列表
double array[] = {112, 111, 23, 456, 231 };
List list = new ArrayList();
List li = new ArrayList();
for (int i = 0; i < array.length; i++) {
list.add(new Double(array[i]));
}
double arr[] = {1131,333};
String str[] = {"dd","aa","bb","cc","ee"};
for(int j=0;j<arr.length;j++){
li.add(new Double(arr[j]));
}
Collections.copy(list,li);
for (int i = 0; i <list.size(); i++) {
System.out.println("list[" + i + "]=" + list.get(i));
}
//结果:1131,333,23,456,231
6) 返回Collections中最小元素(min)
根据指定比较器产生的顺序,返回给定 collection 的最小元素。collection中的所有元素都必须是通过指定比较器可相互比较的
Collections.min(list)
double array[] = {112, 111, 23, 456, 231 };
List list = new ArrayList();
for (int i = 0; i < array.length; i++) {
list.add(new Double(array[i]));
}
Collections.min(list);
for (int i = 0; i <list.size(); i++) {
System.out.println("list[" + i + "]=" + list.get(i));
}
//结果:23
7) 返回Collections中最小元素(max)
根据指定比较器产生的顺序,返回给定 collection 的最大元素。collection中的所有元素都必须是通过指定比较器可相互比较的
Collections.max(list)
double array[] = {112, 111, 23, 456, 231 };
List list = new ArrayList();
for (int i = 0; i < array.length; i++) {
list.add(new Double(array[i]));
}
Collections.max(list);
for (int i = 0; i <list.size(); i++) {
System.out.println("list[" + i + "]=" + list.get(i));
}
//结果:456
8) lastIndexOfSubList
返回指定源列表中最后一次出现指定目标列表的起始位置
int count = Collections.lastIndexOfSubList(list,li);
double array[] = {112, 111, 23, 456, 231 };
List list = new ArrayList();
List li = new ArrayList();
for (int i = 0; i < array.length; i++) {
list.add(new Double(array[i]));
}
double arr[] = {111};
String str[] = {"dd","aa","bb","cc","ee"};
for(int j=0;j<arr.length;j++){
li.add(new Double(arr[j]));
}
Int locations = Collections. lastIndexOfSubList (list,li);
System.out.println(“===”+ locations);
//结果 3
9) IndexOfSubList
返回指定源列表中第一次出现指定目标列表的起始位置
int count = Collections.indexOfSubList(list,li);
double array[] = {112, 111, 23, 456, 231 };
List list = new ArrayList();
List li = new ArrayList();
for (int i = 0; i < array.length; i++) {
list.add(new Double(array[i]));
}
double arr[] = {111};
String str[] = {"dd","aa","bb","cc","ee"};
for(int j=0;j<arr.length;j++){
li.add(new Double(arr[j]));
}
Int locations = Collections.indexOfSubList(list,li);
System.out.println(“===”+ locations);
//结果 1
10) Rotate
根据指定的距离循环移动指定列表中的元素
Collections.rotate(list,-1);
如果是负数,则正向移动,正数则方向移动
double array[] = {112, 111, 23, 456, 231 };
List list = new ArrayList();
for (int i = 0; i < array.length; i++) {
list.add(new Double(array[i]));
}
Collections.rotate(list,-1);
for (int i = 0; i <list.size(); i++) {
System.out.println("list[" + i + "]=" + list.get(i));
}
//结果:111,23,456,231,112
七 同步控制
常见的HashSet,TreeSet,ArrayList,ArrayDeque,LinkList,HashMap,TreeMap都是线程不安全的。
Collections类中提供了 SynchronizedXXX方法可以将指定的集合包装成线程同步的集合。