集合总结
一.collection集合
1.概述:
Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。JDK 不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set 和 List)实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。
2.功能及用法
1.添加功能:
Collection collection = new ArrayList();//多态:父类引用指向子类对象
collection.add(100);//注意100不是基本类型,而是引用类型
bollean b = collection.addAll(collection2);//将collection2中的全部元素归并到collection中
2删除功能:
boolean b = collection.remove(100);
boolean b =collection.removeAll(Collection2)//移除collection中俩个集合的交集元素
collection.clear();//清空集合中所有元素
3.判断功能:
boolean b1 = collection.contains(200);//判断集合中是否有这个元素
boolean b2 = collection.containsAll(collection2)//判断collection中是否包含collection中所有元素
boolean b3 = collection.isEmpty();//判断集合是否为空
4.获取功能(遍历集合):
Iterator iterator =collection.iterator();//迭代器迭代遍历集合元素
while (iterator.hasNext()){
Object next = iterator.next();
System.out.println(next);
}
5.长度功能:
int size = collection.size();//获取集合的长度
6.交集功能:
boolean b = collection.retainAll(collection2);//将俩集合的交集放在collection中
7.把集合转换为数组:
Object[] objects = collection.toArray();//调用转换方法
System.out.println(Arrays.toString(objects));
二.List集合
1.概述:
有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。主要特点有元素有序,允许重复元素。
2.特有功能方法
1.指定索引:
list.add(0,"哈");//将"哈"添加到集合第一个位置
2.移除元素:
list.remove("哈");//根据内容移除
list.remove(0);//根据索引移除
list.remove(Integer.valueOf(2));当索引与内容一样时,可以自行包装移除内容
3.获取元素:
Object o = list.get(1);//根据索引获取元素
System.out.println(o);
4.替换元素:
Object b = list.set(1, "a");//用a替换索引1处的元素,返回值(b)为旧元素
5.遍历List集合:
for (int i = 0; i < list.size(); i++) {
Object o = list.get(i);
System.out.println(o);
}
6.List特有的迭代方式:
ListIterator listIterator = list.listIterator();
while (listIterator.hasNext()){ //正向迭代
Object next = listIterator.next();
System.out.println(next);
}
while (listIterator.hasPrevious()){ //反向迭代之前必须要有正向迭代
Object previous = listIterator.previous();//反向迭代之前不能取新迭代器
System.out.println(previous);
}
2.主要类型
(1)Arraylist
1.特点:
底层数据结构是数组,查询快,增删慢。线程不安全,效率高。
空参构造一个初始容量为 10 的空列表。
2.主要功能:
(1)寻找该元素出现的索引
int i = list.indexOf(2);//返回2第一次出现的索引,如果没有该元素,返回-1
System.out.println(i);
int i1 = list.lastIndexOf(2);//返回2最后一次次出现的索引,如果不包含索引,返回-1
System.out.println(i2);
(2)排序集和中的元素
list.sort(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Integer a1 = (Integer) o1; //强制类型转换
Integer b1 = (Integer) o2;
return a1-b1;
}
}
);
(3)截取和克隆集合中的元素
List list1 = list.subList(0, 3);//截取索引0到3的元素
Object clone = ((ArrayList) list).clone();//克隆全部元素
(4)遍历集合中的元素
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
(2)Vector
1.特点
Vector 类可以实现可增长的对象数组 , Vector 是同步的。
底层数据结构是数组,查询快,增删慢。线程安全,效率低。
构造一个空向量,使其内部数据数组的大小为 10,其标准容量增量为零。
2.主要功能
(1)添加功能
vector.add(111);//添加元素
vector.addElement(222);//将指定的组件添加到此向量的末尾,将其大小增加 1
(2)查找功能
Object o1 = objects.elementAt(0);//返回指定索引处的组件
Object o2 = objects.firstElement();//返回此向量的第一个组件(位于索引 0)处的项)
Object o3 = objects.lastElement();//返回此向量的最后一个组件
(3)移除功能
vector.removeAllElements();//移除全部元素,将其大小设置为0
vector.clear();//移除全部元素
vector.removeElement(111);//移除111元素
vector.removeElementAt(1);//移除1号索引的元素
(3)迭代遍历
Enumeration elements = vector.elements();
while (elements.hasMoreElements()){
Object o = elements.nextElement();
System.out.println(o);
}
(3)LinkedList
1.特有功能:
(1)添加功能
list.addFirst(143);//向集合首位添加元素
list.addLast(555);//向集合末尾添加元素
list.push(123);;//向集合首位添加元素
(2)查找功能
Object first = list.getFirst();//拿取集合首位元素
Object last = list.getLast();//拿取集合中末尾元素
Object peek = list.peek();//拿取集合首位元素
Object poll = list.poll();//拿取集合首位元素并移除
Object pop = list.poll();//拿取集合末尾元素并移除
(4)泛型
1.概述:
泛型是一种把类型明确的工作,推迟到创建对象或调用方法的时候才去明确的特殊的类型。它还可以限定集合存储什么样的引用类型,也参数化类型,把类型当作参数一样的传递。提高了代码的扩展性。
2.泛型的格式 : <数据类型> 这里的数据类型只能是引用数据类型
3.泛型好处:
(1): 把运行时期的问题提前到了编译期间
(2): 避免了强制类型转换
(3):优化了程序设计,解决了黄色警告线
注意:泛型只在编译期有效 但在运行期就擦除了
泛型案例:
public class MyClass<T> { //泛型<T> 把泛型加在类上
T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
public class MyTest {
public static void main(String[] args) {
//把类型明确工作,推迟到创建对象,或调用方法时,才去明确的一种机制
MyClass<String> stringMyClass = new MyClass<>();
stringMyClass.setT("abc");
String t = stringMyClass.getT();
MyClass<Integer> integerMyClass = new MyClass<>();
integerMyClass.setT(100);
Integer t1 = integerMyClass.getT();
System.out.println(t);
System.out.println(t1);
}
}
(5)增强for循环
1.用法:
明确容器中的元素是什么数据类型和容器的名字
for(容器中的元素的数据类型 当前遍历的元素名 : 容器名)
for(Integer ele:list){
System.out.println(ele);
}
(6)数组转换成集合
int[] ar = {10, 20, 30, 40};
List<int[]> i = Arrays.asList(ar);
int[] it = i.get(0);
注意事项:通过asList转换过来的集合,该集合就不能再次添加元素或删除元素,只能获取元素来用。在转换过程中如果你给的是一个元素是基本类型的数组,他是把这个数组对象装到集合里面;如果你给的是一个引用类型的数组,他是把数组的元素取出来,放到集合中;如果你传了两个以上的对象数组,那么他是把两个对象数组,存到集合中。
三.Set集合
1.HashSet
(1)特点
HashSet 底层数据结构是哈希表,但底层使用HashMap集合来存的,元素无序且唯一,线程不安全,效率高。
(2)hashCode
当向 HashSet 集合中存入多个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。
当两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等,那么这俩个对象相等,只录入一个对象。
因此HashSet 保证元素唯一性是靠元素重写hashCode()和equals()方法来保证的,如果不重写则无法保证。
案例演示如下:
@Override
public int hashCode() {
return this.name.hashCode() + this.age;//因为成员变量值影响了哈希值,所以我们把成员变量值相加即可
return this.name.hashCode() + this.age * 33;//有时为了区分更准确,我们可以把它们随变乘以一些整数
}
@Override
public boolean equals(Object obj) {
// System.out.println(this + "---" + obj);
if (this == obj) {
return true;
}
if (!(obj instanceof Student)) {
return false;
}
Student s = (Student) obj;
return this.name.equals(s.name) && this.age == s.age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
2.LinkedHashSet
LinkedHashSet 底层数据结构是链表和哈希表 元素有序且唯一 链表保证了有序,哈希表保证了唯一, 线程不安全效率高,用法和HashSet类似
3.TreeSet
(1)特点:
构造一个新的空 set,该 set 根据其元素的自然顺序进行排序。
(2)排序:
a.自然排序:
使用空参构造,他的要求就是元素必须实现 Compareble接口,重写compareTo方法 ,根据此方法的返回值的正 负 0 来决定元素的放置位置
案例演示:
public class Student implements Comparable<Student>//假设有个学生类实现Comparable接口,就要重写compareTo方法
public int compareTo(Student student){
return 1;//返回正值正序排列,负值则倒序排列,0则只会出现一个元素
}
b.比较器排序:
采用有参构造,你在创建TreeSet对象时,需要传入一个Comparetor 比较器,重写比较器里面的compare方法,根据此方法的返回值的正负 0 来决定元素的放置顺序
案例演示
TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() { //构造一个新的空 TreeSet,它根据指定比较器进行排序。
@Override
public int compare(Student s1, Student s2) { // 比较用来排序的两个参数
//根据姓名长度来排序
int num = s1.getName().length() - s2.getName().length();
int num2=num==0?s1.getName().compareTo(s2.getName()):num;
int num3=num2==0?s1.getAge()-s2.getAge():num2;
return num3;
}
}); //通过匿名内部类来传入
四.Map集合
1.Map接口概述
将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值,键相同,值覆盖
Map接口和Collection接口异同:
(1)Map是双列的,Collection是单列的
(2)Map的键唯一,Collection的子体系Set是唯一的
(3)Map集合的数据结构针对键有效,跟值无关;Collection集合的数据结构是针对元素有效
2.HashMap集合
1.概述
HashMap 键的 数据结构是哈希表,键唯一(键唯一,靠键重写equals方法,来保证,合理的 重写hashCode方法,是想让元素,减少碰撞) 无序
HashMap 允许存储null键和null值 线程不安全效率高
2.功能及用法
(1)添加功能
HashMap<String, Integer> map = new HashMap<>();
Integer c = map.put("abc", 1);//当我们第一次存储键值对 数据时,返回的时null
System.out.println(c); //输出null
Integer c1 = map.put("abc", 5);//当我们再次存储一个键相同的数据时,会覆盖掉旧值,返回值,上一次这个键所对应的旧值
System.out.println(c1); //输出1
(2)删除功能
Integer abc = map.remove("abc");//根据键删除键值对元素,并把值返回
map.clear();//删除全部键 值对元素
(3)判断功能
boolean b = map.containsKey("abc");//判断集合是否包含指定的键
boolean b1 = map.containsValue(2);//判断集合是否包含指定的值
boolean empty = map.isEmpty();//判断集合是否为空
(4)获取功能
Integer abe = map.get("abe");//获取该键对应的值
int size = map.size(); //获取集合的长度
Set<String> keySet = map.keySet();//获取所有键的集合
Collection<Integer> values = map.values();//获取所有值的集合
Set<Map.Entry<String, Integer>> entries = map.entrySet();//获取所有键 值对
Set<String> strings = map.keySet();//获取所有键的集合
(5)遍历方式
a.遍历方法1
Set<String> strings = map.keySet();//获取所有键的集合
for (String s : strings) {
System.out.println(s+"===="+map.get(s)); //获取所有键 值对的集合
}
b.遍历方法2
Set<Map.Entry<String, Integer>> entries = map.entrySet();//获取所有键 值对的集合
for (Map.Entry<String, Integer> entry : entries) {
String key = entry.getKey();//获取键
Integer value = entry.getValue();//获取值
System.out.println(key+"======="+value);
}
3.Hashtable和HashMap 的区别
1.HashMap 允许存储null键和null值 线程不安全效率高
2.Hashtable 不允许null键和null值 线程安全效率低
3.其它用法基本相同
3.LinkedHashMap集合
Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序,功能用法和HashMap相同
底层的数据结构是链表和哈希表 元素有序 并且唯一(元素的有序性由链表数据结构保证 唯一性由 哈希表数据结构保证)
4.TreeMap集合
键的数据结构是二叉树,可保证键的排序和唯一性
排序分为自然排序和比较器排序
线程是不安全的效率比较高
排序方式与TreeSet相同
其它功能与HashMap类似
五.集合嵌套
部分源代码:
for (HashMap<String, String> hm : maxList) {
Set<Map.Entry<String, String>> entries = hm.entrySet();
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"-----"+value);
}
System.out.println();
}
六.Collections工具类
1.打乱集合顺序
Collections.shuffle(new ArrayList<>());//随机打乱集合中元素的顺序
2.排序
ArrayList<Integer> list = new ArrayList<>();//排序
list.add(111);
list.add(222);
list.add(333);
Collections.sort(list);
System.out.println(list);
3.二分查找
int i = Collections.binarySearch(list,222);//查找元素,返回位置
七.集合的并发修改异常(ConcurrentModificationException)
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
at org.westos.demo.Mytext2.main(Mytext2.java:20)
1.造成原因:
原因是我们的迭代依赖于集合 当我们往集合中添加好了元素之后 获取迭代器 那么迭代器已经知道了集合的元素个数
这个时候你在遍历的时候又突然想给 集合里面加一个元素(用的是集合的add方法) 那迭代器不同意 就报错了
2.解决方法:
解决方案1:
我们用ListIterator迭代器遍历 用迭代器自带的add方法添加元素 那就不会报错了 解决
将迭代器中的list.add(2)换成listIterator.add(2)
解决方案2:
使用for循环遍历集合 添加元素 不会报错