一、概述
1、为什么会出现集合类?
面向对象语言对事物的描述都是以对象的形式,为了方便对多个对象的操作,就需要对对象进行存储,集合就是存储对象最常用的一种方式。
2、数组和集合类都是容器,有什么区别呢?
1,数组长度是固定的,集合长度是可变的。
2,数组可以存储对象,也可以存储基本数据类型,集合只能存储对象。集合可以存储不同类型的对象。
3、集合体系
collection
|——List 有序(存入的顺序和取出的顺序一致)。有索引。允许重复元素。
| |——LinkedList
| |——ArrayList
| |——Vector
| |——Stack
|——Set 不允许重复元素。
Map
|——HashTable------线程安全,低效,不支持null
|——HashMap--------非线程安全,高效,支持null
|——WeakHashMap
二Collection接口中的共性功能
1,添加
boolean add(Object obj); //一次添加一个
boolean addAll(Collection coll); //将指定容器中的所有元素添加到容器中
2、删除
void clear(); //
boolean remove(Object obj); //删除此Collection中指定的元素。如果存在。
boolean removeAll(Collection coll); //删除此Collection中所有包含在指定Collection中的所有元素。
boolean retainAll(Collection coll); c1.retainAll(c2); 将c1和c2不同的元素从c1中删除,保留c1中和c2中相同的元素。
3,获取长度
int size();
4,判断
boolean isEmpty(); //判断集合是否为空
boolean contains(Object obj); //判断集合中是否包含此对象
boolean containsAll(Collection coll); //如果此Collection包含指定Collection中的所有元素,则返回true
5,将集合转换成数组
toArray()
toArray([])
6,取出集合元素
Iterator iterator()
获取集合中元素上迭代功能的迭代器对象
迭代:取出元素的一种方式。有没有?有!取一个。还有没有?有!取一个。还有没有?没有!算了。
迭代器:具备着迭代功能的对象。
而迭代器对象不需要new 。直接通过iterator()方法获取即可
迭代器是取出Collection集合中元素的公共方式。
7,Iterator迭代器包含的方法
hasNext() 如果迭代器指向位置后面还有元素,则返回true,否则返回false
next() 返回集合中Iterator指向位置后面的元素,同时迭代器指向位置后移
remove() 删除集合中Iterator指向位置后面的元素
8,List接口中的特有方法:它的特有方法都是围绕索引定义的
增:
add(index,element);
删:
remove(index);
改:
set(index,element);
查:
int indexOf(element);
element get(index);
9,List集合特有的取出方式
for(int i = 0; i<list.size();i++){
list.get(i);
}
for(Iterator it = list.iterator();it.hasNext();){
it.next();
}
ListIterator是List集合的特有的迭代器,通过List集合的方法listIterator()获取该迭代器对象。
ListIterator可以实现迭代过程中的增删改查
10,解决在遍历过程中要对集合进行操作产生异常的问题
由于迭代过程中使用了集合对象同时对元素进行操作,导致迭代的不确定性,引发了该异常。(java.util.ConcurrentModificatException)
解决思想:在迭代的过程中,想要执行一些操作,使用迭代器的方法就可以了。
for(ListIterator it = list.listIterator();it.hasNext();){
Object obj = it.next();
if(obj.equals("")){
it.add("");
}
}
三、List集合的使用
1,List集合的常用子类
List集合的具体子类,子类之所以区分是因为内部的数据结构(存储数据方式)不同
|--Vector 数据结构是数组,数组是可变长度的(不断new新数组并将原数组元素复制到新数组中)。线程是同步的。无论增删还是查询,都慢。
|--ArrayList 也是数组结构,也是长度可变的。线程不同步,替代了vector,增删速度不快,查询速度很快(在内存中连续存储)
|--LinkedList 链表结构,线程不同步的,增删速度快。查询速度较慢。
2、使用ArrayList去除集合中的重复元素。
方式一:
<span style="white-space:pre"> </span>public static void singleElement(){
for(int x = 0;x = list.size()-1;x++){
Object obj_x = list.get(x);
for(int y = x + 1;y=list.size();y++){
if(obj_x.equals(list.get(y))){
list.remove(y);
y--;
}
}
}
}
方式二:
思路:
1,最后唯一性的元素也很多,可以先定义一个容器用于存储这些唯一性的元素
2,对原有容器进行元素获取,并到临时容器中判断是否存在。容器本身就有这个功能,判断元素是否存在
3,如果存在就不存储,如果不存在就存储。
4,遍历完原容器后,临时容器中存储的就是唯一性元素。
public static void singleElement(List list){
//定义一个临时容器
List temp = new ArrayList();
//2,遍历原容器
for(Iterator it = list.iterator();it.hasNext();){
Object obj = (Object)it.next();
//3,在临时容器中判断遍历到的元素是否存在。
if(!temp.contains(obj)){
//4,如果不存在,就存储到临时容器中
temp.add(obj);
}
}
//5,将原容器清空
list.clear();
//6,将临时容器中的元素都存储到原容器中
list.add(temp);
}
3,LinkedList特殊的方法
添加方法:addFirst(); 将指定元素插入到此列表的开头
addLast(); 将指定元素添加到此列表的结尾
获取元素:
getFirst(); 返回列表的第一个元素。
getLast(); 返回列表的最后一个元素。
删除元素:
removeFirst(); 移除并返回此列表的第一个元素。
removeLast(); 移除并返回此列表的最后一个元素。
四、Set集合的使用
|--HashSet 哈希表(散列)结构,
|--TreeSet 可以对元素进行排序
1,存储原理:
set集合存储元素时,经过Hash算法计算Hash值,然后根据hash值把元素存储到特定的位置。查询时,计算hash值,根据hash值查询元素。2,元素为什么是唯一的:
不允许存储重复元素,防止发生查找的不确定性。不保证存入和取出的顺序一致
3,特点:
比数组的查询效率高4,相关概念:
1、 用于存储元素和哈希值对应关系的容器称之为哈希表2、Hash冲突
当哈希算法算出两个元素的值相同时,称为哈希冲突
冲突后,需要对元素进行进一步的判断,判断的是元素的内容,equals进行判断
哈希表在判断元素是否相同:依据hashCode()方法,如果哈希值冲突(哈希值相同),再判断元素的equals方法。如果equals返回true,不存储,返回false,存储。
5,set集合存储自定义的对象时,如何保证唯一性。
元素必须覆盖hashCode和equals方法覆盖hashCode方法是为了根据元素自身特点确定哈希值。
覆盖equals方法是为了解决哈希值的冲突
五、Map集合的使用
1、共性的功能
1,添加
V put(K key,V value); //如果键值对时,如果键相同,会出现值覆盖。 返回值:与key关联的旧值;如果key没有任何映射关系,则返回null
putAll(Map<k,v> map);
2,删除
void clear();
V remove(K key); //返回被删除key关联的value 获取的同时删除
3,判断
boolean containsKey(Object obj);
boolean containsValue(Object obj);
boolean isEmpty();
4,获取
V get(K key); //根据键获取对应的值
int size();
5、获取所有
Collection<V> values(); //返回此映射中包含的值的Colleciton视图
Set<K> keySet(); //返回此映射中包含的键的Set视图
Set<Map.Entry<K,V>> entrySet(); //返回此映射中包含的映射关系的Set视图
2、如何取出Map中所有的元素。
1、keyset() 返回所有的键Map集合没有迭代器。但是可以将Map集合转成Set集合,再使用迭代器进行迭代获取。
Set<K> keyset() //取出所有的键,并存储到set集合中 因为Map中键具有唯一性,所以set集合
流程:
Map---->keyset()------>Set<Key>------>iterator------>map.get(key);
代码:
Set<String> keySet = map.keySet();
for(Iterator<String> it = keySet.iterator();it.hasNext();){
String key = it.next();
String value = map.get(key);
}
2、entrySet() //返回所有的键值对(此映射中包含的映射关系的set视图)
Map.Entry:其实就是Map接口中的一个内部接口,
流程:
map ---->entrySet()----->Set<Map.Entry<>>---->iterator-----Map.Entry<>---->getKey();getValue();
代码:
Set<Map.Entry<String,String> entrySet = map.entrySet();
for(Iterator<Map.Entry<String,String>> it = entrySet.iterator();it.hasNext()){
Map.Entry<String,String> me = it.next();
String key = me.getKey();
String value = me.getValue();
}
3、Map集合的常见子类
|--HashTable: 哈希表,是同步的,不允许null键和null值|--LinkedHashMap:保留插入的顺序,如果需要输出的顺序和输入时的相同,就选用LinkedHashMap
|--HashMap: 哈希表,是不同步的,允许null键和null值
|--TreeMap: 二叉树,是不同步的,可以对Map集合中的键进行排序
4、Map集合的应用
当需求中出现映射关系时,就应该最先想到Map集合5、Map集合Demo
需求:获取字符串中每一个字母出现的次数,要求格式:a(2)b(1)d(3).....思路:
1,获取字符串中的字母
2,获取字母次数
字母和次数有对应关系,而且对应关系的一方具备唯一性。
使用Map集合,Map集合实际上就是一张表。
3,使用查表法
先查第一个字母在表中的次数,如果次数不存在,说明是第一次出现,将该字母和1存储到表中
依次类推。当要查询的字母次数存在,将次数取出自增后,再和对应的字母存储到表中,map的特点是键相同,值会被覆盖。
4,查完每一个字母后,表中存储的就是每一个字母出现的次数。
代码:
String str = "";
String charCount = getCharCount(str);
public static String getCharCount(String str){
//1,将字符串转成字符数组
char[] chs = str.toCharArray();
//2,定义map集合
Map<Character,Integer> map = new TreeMap<Character,Integer>();
//记录次数
int count = 0;
//3,遍历字符数组,获取每一个字母
for(int i = 0;i < chs.length;i++){
//将遍历到的字母作为键去查表,获取值。
Integer value = map.get(chs[i]);
//如果次数存在,就用count记录该次数,如果次数不存在,就不记录,只对count进行自增。
if(value!=null){
count++;
}
count++;
map.put(chs[i],count);
}
}
六、Arrays,操作数组的工具类
1、常用方法
1,复制数组
copyOf(original,newLength) 返回原数组的副本,截取或用0填充以获得指定的长度。 original:要复制的数组 newLength:要返回副本的长度public static byte[] copyOf(byte[] original,int length)
2,数组是否相等
equals(a1,a2) 如果两个数组相等,则返回true3,填充数组
fill(a,val) a:要填充的数组 val:要存储在数组所有元素中的值。public static void fill(int[] a,int val) 将指定的 int 值分配给指定 int 型数组的每个元素。
4,排序
sort(a) 参数:a要排序的数组5,格式为字符串形式。
toString(a) 返回a的字符串表示形式 参数a - 返回其字符串表示形式的数组2、数组和集合的相关转换
1、数组转成集合
Arrays.asList(a); 返回一个受指定数组支持的 固定大小 的列表 参数a 数组
注意:
1,如果数组中都是引用数据类型,转成集合时,数组元素直接作为集合元素。
如果数组中都是基本数据类型,会将数组对象作为集合中的元素。
java.lang.UnsupportedOperationException
不能使用集合的增删方法,因为是固定大小的列表,所以不能改变长度。
int[] arr = {45,27,78,15,99}; 基本数据类型
List<int[]> list = Arrays.asList(arr);
list.get(0); 地址值
Integer[] arr = {45,27,78,15,99}; 引用数据类型
List<Integer> list = Arrays.asList(arr);
list.get(0); 45
2、集合转成数组
Collection中的toArray方法
List<T> list = new ArrayList<T>();
list.add();
list.add();
T[] arr = list.toArray(new T[list.size()]);
注意:
传入的数组的长度,如果小于集合的长度,方法中会创建一个新的数组,新数组的长度和集合的长度一致。
如果传入的数组长度大于等于集合长度,会使用方法中传入的数组。所以建议长度定义为集合的size