目录
1.List集合
特点:元素有序,可重复。
三种遍历:下标,foie循环,迭代器。
扩容:
初始容量10 , 负载因子0.5,扩容增量0.5倍
新容量 = 原容量 + 原容量 * 0.5 , 如 ArrayList的容量为10,一次扩容后是容量为15实现类:ArrayList . LinkedList . Vector . CopyOnWriteArrayList
ArrayList:1.动态数组,自动扩容。线程不安全。不适合随机增加和删除。
定义一个数组。如下:
package com.zking.demo.test; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.junit.Before; import org.junit.Test; public class ListDemo { private List<Integer> list; @Before public void Demo01() { list=new ArrayList<Integer>(); list.add(1); list.add(2); list.add(3); list.add(3); list.add(4); list.add(5); } }
ArrayList正确删除元素的三种方法:
第一种(for循环):
@Test public void Demo02() { System.out.println("删除前:"+list); for (int i = list.size()-1; i >=0 ; i--) { if(list.get(i)==3) { Integer remove = list.remove(i); } } System.out.println("删除后:"+list); }
第二种(迭代器):
@Test public void Demo03() { System.out.println("删除前:"+list); Iterator<Integer> iterator = list.iterator(); while(iterator.hasNext()) { if(iterator.next()==3) { iterator.remove(); } } System.out.println("删除后:"+list); }
第三种(for循环):
@Test public void Demo04() { System.out.println("删除前:"+list); for (int i = 0; i < list.size(); i++) { if(list.get(i)==3) { list.remove(i--); } } System.out.println("删除后:"+list); }
结果是:
ArrayList错误删除方式:
第一种(相邻且相同无法删除):
@Test public void Demo05() { System.out.println("删除前:"+list); for (int i = 0; i < list.size(); i++) { if(list.get(i)==3) { list.remove(i); } } System.out.println("删除后:"+list); }
结果是:
看上面这张图,还有个元素3没有删除掉,出现这个错误是因为在删除第一个元素3之后后面的元素会挤上来,下标随之改变-1,相邻的第二个3就从下标为3变成了下标为2,从而第二个元素3就没有删掉。
第二种方式(有重复元素无法删除):
@Test public void Demo06() { System.out.println("删除前:"+list); for (Integer integer : list) { if(integer==3) { list.remove(integer); } } System.out.println("删除后:"+list); }
第三种方式(有重复元素无法删除):
Iterator<Integer> it=list.iterator(); while(it.hasNext()){ Integer value=it.next(); if(value==3){ list.remove(value); } }
结果都是:
第四种方式(根据下标删除):
@Test public void Demo07() { System.out.println("删除前:"+list); list.remove(1); System.out.println("删除后:"+list); }
结果是:
LinkedList
LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部
线程不安全
LinkedList可被用作堆栈(stack)【包括了push,pop方法】,队列(queue)或双向队列(deque)
以双向链表实现,链表无容量限制,允许元素为null,线程不安全
适合做随机的增加或删除
Vector
线程安全
并行性能慢,不建议使用
CopyOnWriteArrayList
写时复制
线程安全
适合于读多,写少的场景
写时复制出一个新的数组,完成插入、修改或者移除操作后将新数组赋值给array
比Vector性能高
最终一致性
实现了List接口,使用方式与ArrayList类似
2.Set集合
特点:无序,不可重复。
扩容: 初始容量16,负载因子0.75,扩容增量1倍
实现类:HashSet . TreeSet
HashSet:
1.不重复,无序,允许空值。:依据对象的hashcode来确定该元素是否存在
2.底层是hashMap实现。
3.线程不安全
4.性能参数:初始容量,负载因子
默认值: 初始容量16,负载因子0.75
示例:new HashSet<>(20, 0.5f);遍历:fore循环,迭代器。
实体类:
package com.zking.demo.entity; public class Student { private Integer id; private String name; private Integer age; public Student() { // TODO Auto-generated constructor stub } public Student(Integer id, String name, Integer age) { super(); this.id = id; this.name = name; this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", age=" + age + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((age == null) ? 0 : age.hashCode()); result = prime * result + ((id == null) ? 0 : id.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (age == null) { if (other.age != null) return false; } else if (!age.equals(other.age)) return false; if (id == null) { if (other.id != null) return false; } else if (!id.equals(other.id)) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } }
//fore循环遍历 @Test public void demo03() { Set<Student> set =new HashSet<>(); set.add(new Student(1, "xm", 18)); set.add(new Student(1, "xm", 18)); set.add(new Student(2, "xh", 19)); set.add(new Student(2, "xh", 19)); set.add(new Student(3, "xl", 20)); set.add(new Student(3, "xl", 20)); for (Student student : set) { System.out.println(student); } } //迭代器遍历 @Test public void demo04() { Set<Student> set =new HashSet<>(); set.add(new Student(1, "xm", 18)); set.add(new Student(1, "xm", 18)); set.add(new Student(2, "xh", 19)); set.add(new Student(2, "xh", 19)); set.add(new Student(3, "xl", 20)); set.add(new Student(3, "xl", 20)); Iterator ite=set.iterator(); while(ite.hasNext()) { System.out.println(ite.next()); } }
结果是:
这个结果是因为Student学生实体实现了 hashCode() , equals()方法。
如果不实现这两个方法,那么就不会自动去重。则就是如下图:
如果自定义实体类对象的属性有很多,20个、30个等等,那么我们只需要重写equals和hashcode方法里面特定的几个属性,只要足够判断去重就可以了。
比如上面Student类是三个属性,但判断学生类去重只需要重写hashcode和equals方法中的一个编号就可以了。
也就是如下实体类代码:
package com.zking.demo.entity; public class Student { private Integer id; private String name; private Integer age; public Student() { // TODO Auto-generated constructor stub } public Student(Integer id, String name, Integer age) { super(); this.id = id; this.name = name; this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", age=" + age + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((id == null) ? 0 : id.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (id == null) { if (other.id != null) return false; } else if (!id.equals(other.id)) return false; return true; } }
TreeSet
是一个包含有序的且没有重复元素的集合
作用是提供有序的Set集合,自然排序或者根据提供的Comparator进行排序
TreeSet是基于TreeMap实现的
思考:list集合怎么去重?
答案:借助set集合。首先先将list集合对象通过set集合的构造函数转化为set集合对象,再通过同样的操作将set集合对象通过list集合的构造函数转化为list集合对象就可以了。
例如:
package com.zking.demo.test; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import org.junit.Before; import org.junit.Test; public class Set { private List<Integer> list=new ArrayList<Integer>(); @Before public void demo01() { list.add(1); list.add(1); list.add(2); list.add(3); list.add(3); } @Test public void demo02() { List<Integer> list=new ArrayList<>(new HashSet<>(this.list)); System.out.println(list); } }
Set集合想要排序,就要借助它的实现类treeSet来进行排序。(默认是自然排序)
@Test public void demo05() { Set<Integer> set=new TreeSet<>(); set.add(1); set.add(3); set.add(4); set.add(6); set.add(2); set.add(5); for (Integer integer : set) { System.out.println(integer); } }
结果是:
如果想要倒序排序就需要用到比较器Comparator,可以实现也可以通过构造方法传入。
下面是通过构造方法:
@Test public void demo05() { Set<Integer> set=new TreeSet<>(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { // TODO Auto-generated method stub return o2-o1; } }); set.add(1); set.add(3); set.add(4); set.add(6); set.add(2); set.add(5); for (Integer integer : set) { System.out.println(integer); } }
结果就是:
那如果是对象呢?该通过什么方式排序?
就比如Student学生类,通过构造方法传入比较器之后,通过对象的属性来比较大小进行排序
如下通过年龄来进行排序:
@Test public void demo06() { Set<Student> set=new TreeSet<>(new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return o2.getAge()-o1.getAge();//通过学生的年龄来进行排序。 } }); set.add(new Student(1, "xm", 18)); set.add(new Student(2, "xh", 19)); set.add(new Student(3, "xl", 20)); set.add(new Student(4, "xx", 21)); Iterator ite=set.iterator(); while(ite.hasNext()) { System.out.println(ite.next()); } }
结果是:
但有一个小细节需要注意,如果出现同样年龄的人,就会漏掉一个学生。所以我们得在做一个判断,当学生的年龄相同时,用一个特有属性再进行排序即可。
如下:
@Test public void demo06() { Set<Student> set=new TreeSet<>(new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { if(o2.getAge()==o1.getAge()) { return o2.getId()-o1.getId();//再通过编号进一步排序。 } return o2.getAge()-o1.getAge();//通过学生的年龄来进行排序。 } }); set.add(new Student(1, "xm", 18)); set.add(new Student(2, "xh", 19)); set.add(new Student(3, "xl", 20)); set.add(new Student(4, "xx", 20)); Iterator ite=set.iterator(); while(ite.hasNext()) { System.out.println(ite.next()); }
结果是:
这样就不会漏掉数据了。
就比如Student学生类,通过实现比较器接口,通过对象的属性来比较大小进行排序
如下通过年龄来进行排序:
实体类:
package com.zking.demo.entity; import java.util.Comparator; public class Student implements Comparable<Student> { private Integer id; private String name; private Integer age; public Student() { // TODO Auto-generated constructor stub } public Student(Integer id, String name, Integer age) { super(); this.id = id; this.name = name; this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", age=" + age + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((id == null) ? 0 : id.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (id == null) { if (other.id != null) return false; } else if (!id.equals(other.id)) return false; return true; } @Override public int compareTo(Student o) { if(o.getAge()==this.getAge()) { return o.getId()-this.getId(); } return o.getAge()-this.getAge(); } }
测试类:
@Test public void demo06() { Set<Student> set=new TreeSet<>(); set.add(new Student(1, "xm", 18)); set.add(new Student(2, "xh", 19)); set.add(new Student(3, "xl", 20)); set.add(new Student(4, "xx", 20)); Iterator ite=set.iterator(); while(ite.hasNext()) { System.out.println(ite.next()); } }
结果是一样的:
如果实体类实现了比较器接口Comparabled,而测试方法通过构造方法传入了构造器,那么是构造方法的生效。
3.Mep集合
特点:
无序,键值对,键不能重复,值可以重复,
键重复则覆盖,没有继承Collection接口扩容:初始容量16,负载因子0.75,扩容增量1倍
遍历
先获取所有键的Set集合,再遍历(通过键获取值)
取出保存所有Entry的Set,再遍历此Set即可
hashMap:
第一种遍历方式,通过keySet()获取所有键Set集合,然后遍历再得到值。
如下:
@Test public void demo01() { map.put("1", "小明"); map.put("2", "小明2"); map.put("3", "小明3"); map.put("4", "小明4"); Iterator<String> iterator = map.keySet().iterator(); while(iterator.hasNext()) { String key = iterator.next(); Object value = map.get(key); System.out.println(value); } }
结果是:
第二种遍历方式:通过entrySet()方法,得到所有键值对对象的Set集合,然后通过迭代器遍历分别得到键和值。
如下:
@Test public void demo02() { map.put("1", "小明"); map.put("2", "小明2"); map.put("3", "小明3"); map.put("4", "小明4"); Set<Entry<String,Object>> entrySet = map.entrySet(); Iterator<Entry<String, Object>> iterator = entrySet.iterator(); while(iterator.hasNext()) { Entry<String, Object> next = iterator.next(); System.out.println("key:"+next.getKey()+"-----"+"value:"+next.getValue()); }
结果是:
HashTable
线程安全,不太常用 ,效率慢。
ConcurrentHashMap
线程安全,比HashTable性能高
TreeMap
key值按一定的顺序排序
添加或获取元素时性能较HashMap慢
因为需求维护内部的红黑树,用于保证key值的顺序代码如下:
@Test public void demo03() { Map<String, Object> treeMap=new TreeMap<>(new Comparator<String>() { @Override public int compare(String o1, String o2) { // TODO Auto-generated method stub return o2.compareTo(o1); } }); treeMap.put("1", "小明"); treeMap.put("2", "小明2"); treeMap.put("3", "小明3"); treeMap.put("4", "小明4"); Set<Entry<String,Object>> entrySet = treeMap.entrySet(); Iterator<Entry<String, Object>> iterator = entrySet.iterator(); while(iterator.hasNext()) { Entry<String, Object> next = iterator.next(); System.out.println("key:"+next.getKey()+"-----"+"value:"+next.getValue()); } }
结果:
默认是升序排序,而上面o1和o2调货了位置,则变成了降序。
LinkedHashMap:
LinkedHashMap是有序的,且默认为插入顺序
当我们希望有顺序地去存储key-value时,就需要使用LinkedHashMap了代码如下:
@Test public void demo04() { Map<String, String> linkedHashMap = new LinkedHashMap<>(); linkedHashMap.put("name1", "josan1"); linkedHashMap.put("name2", "josan2"); linkedHashMap.put("name3", "josan3"); Set<Entry<String, String>> set = linkedHashMap.entrySet(); Iterator<Entry<String, String>> iterator = set.iterator(); while(iterator.hasNext()) { Entry entry = iterator.next(); String key = (String) entry.getKey(); String value = (String) entry.getValue(); System.out.println("key:" + key + ",value:" + value); } }