List
元素有序,且可重复
遍历方法:1-for循环通过下标遍历 2-foreach遍历 3-使用迭代器遍历 4-使用lambda遍历
扩容:初始容量10,负载因子0.5,扩容增量0.5被 新容量=旧容量+旧容量*0.5或者新容量=旧容量*1.5
实现
ArrayList
1 简单数据结构,超出容量会自动扩容。所以在我们看来ArrayList的空间是无线大的,动态数据
2 内部实现是基于基础的对象数组
3 随机访问块
4 不适合随机的增加或者删除(因为ArrayList是一个对象数据,数据一旦要修改整个数据位置都会改动)
5 线程不安全(因为整个方法没有锁)
Listls=new ArrayList (); List ls=new ArrayList<>(); // 输出方式1 使用遍历输出 for (Student su : ls) { System.out.println(su); } // 输出方式2 使用for循环输出 for (int i = 0; i < ls.size(); i++) { System.out.println(ls.get(i)); } //输出方式3 使用迭代器输出 Iterator lt= ls.iterator(); //判断是否有下一位 if(lt.hasNext()) { //得到它的下一位 lt.next(); System.out.println(lt); } //输出方式4 使用lambda表达式 ls.forEach(l->System.out.println(l)); //BeFore是在每个测试方法之前执行 @Before public void stati() { ls.add(new Student("11",1)); ls.add(new Student("22",2)); ls.add(new Student("33",3)); ls.add(new Student("44",4)); ls.add(new Student("55",5)); ls.add(new Student("66",6)); } //test方法代表的是你在运行这个方法时,就只能运行你所选中的方法。其他的test方法是不能运行的,这样比较好测试 @org.junit.Test public void text01() { //遍历 删除 //当使用遍历删除集合时,要用break来终止循环,否则报错 //因为你遍历的是原来的数组,你进行删除后。list这个集合里面的数据已经发生改变了,必须使用break来终止循环 for (Student s : ls) { if(s.getSid()==1) { ls.remove(s); break; } } //输出 ls.forEach(t->System.out.println(t)); } @org.junit.Test public void text02() { //使用迭代器进行删除 Integer a[]= {1,3,65,3,23,231,5,4,9};//定义一个数组 List ls=Arrays.asList(a);//把数组放到一个集合里面 Iterator it= ls.iterator();//使用 迭代器 while(it.hasNext()) {//判断是否有下一个 Integer s= it.next();//如果有下一个值 if(s==1) {//判断值是否为1 it.remove();//如果等于就删除 //执行完毕后会报错,因为Arrays里面没有remove这个方法 可以看看源代码。但是我们为什么可是使用remove方法代码而不报错,因为Arrays里面继承了Arraylist接口。 //所以我们必须使用下一种方法 } } } @org.junit.Test public void text03() { //使用迭代器删除 Integer a[]= {1,3,4,2,5,4}; List ls=new ArrayList<>(Arrays.asList(a));//这里我使用的是Arraylist,在ArrayList里面放了一个Arrays集合。这样我们就不会报错了 Iterator it= ls.iterator(); while(it.hasNext()) { Integer s= it.next(); if(s==1) { it.remove(); break; } } ls.forEach(e->System.out.println(e)); } @org.junit.Test public void text04() { //使用流的方式删除 //从第一个开始,如果id不为1,则就保存到新的list集合中 filter过滤条件 List a= ls.stream().filter(t-> t.getSid()!=1).collect(Collectors.toList()); //输出 a.forEach(e->System.out.println(e)); } //java的引用传递 @org.junit.Test public void text05() { //当我们需要对一个集合进行修改时,要保证之前的集合不会被修改就需要使用深度拷贝 List lss=updata02(ls); lss.forEach(s->System.out.println(s)); System.out.println("=========="); ls.forEach(a->System.out.println(a)); } //深度拷贝(克隆) //1使用json传递 private List updata02(List o ){ String json= JSON.toJSonString(o);//这里需要一个json工具包,我这里使用的是阿里的json工具包fastjson //复制一个新的集合 List ls= JSON.parseArray(json,Student.class); //开始遍历 for (Student s : ls) { s.setName("1111"); } return ls; }
linkedList
1 linkedList额外提供了一些方法。比如addFirst 在集合最前面增加一组数据,addLast 在集合最后面增加一组数据,以及remove和insert方法等等
2 linkedList可用作堆栈(stack)包括了push和pop方法 队列queue 或双向队列deque
3 以双向对象实现,所以能够很好的实现增加或者删除。链表无容量限制,允许元素为空
4 适合最随机的增加或者删除
5 线程不安全(方法里面没有锁)
java.util.linkedListl=new java.util.linkedList<>(); @Test public void text01() { //linkedlist的方法基本与ArrayList方法一致 l.addFirst(new Student("1", 1));//在集合的最前面增加一组数据 l.addLast(new Student("2", 2));//在集合的最后面增加一组数据 }
Vector
线程安全(说白了在每个方法里面都加了锁)并行效率慢,不建议使用。方法与ArrayList差不多
CopyOnwiterArrayList
1 写时复制
2 线程安全
3 适合读多写少的场景(我查阅了很多数据,在数据很多的适合还是不适合写)
4 写时复制一个新的数据,在这个新的数组里面完成增加或者修改删除,后将新数组赋值给旧数组。最终完成数据一致性
5 比Vector性能高(虽然copyonwiterarraylist里面的方法也有所,但是它是写时赋值一个新的数组。在用户未完成新数组修改的方法后,其他用户还是访问的是旧数组。两边都不耽误)
6 最终一致性
7 继承了List接口,使用方法与ArrayList基本一致(你只要会用ArrayList就会copyonwiterarraylist)
Set
特点:无序,不重复
遍历:foreach,迭代器,下标,lambda表达式。方法基本与list一致
扩容:初始容量为16,负载因子0.75。扩容增加一倍
实现
HashSet
1 它存储唯一元素并允许空值,依据对象的hashcode来判断该元素是否存在
2 由HashMap支持
3 不保存插入顺序
4 非线程安全(方法也没有锁)
private Sets=new HashSet<>(); @Before public void set() { //增加 s.add(new Student("1", 1)); s.add(new Student("2", 2)); s.add(new Student("3", 3)); s.add(new Student("4", 4)); s.add(new Student("5", 5)); } @Test public void text01() { //注意,要在对象里面实现equals和hashCode方法。要不然还是会能增加重复的数据 s.add(new Student("1", 1));//我这里已经实现了这两个方法,所以数据不会重复增加 s.forEach(t->System.out.println(t)); } //Set深度拷贝 @Test public void text05() { String json= JSON.toJSonString(s); Set p= JSON.parseObject(json,new TypeReference >() {}); for (Student s : p) { if(s.getSid()==1) { p.remove(s); break; } } System.out.println("之前的数据"); s.forEach(z->System.out.println(z)); System.out.println("现在的数据"); p.forEach(c->System.out.println(c)); }
TreeSet
1 是一个有序的,且不包含重复的额元素的集合
2 作用是根据根据有序的Set集合,自然排序或者根据提供的Comparator进行排序
3 TreeSet是基于TreeMap实现的
Map
特点:无序,键值对。键不可以重复,值可以重复。键如果重复则覆盖,没有继承Collection接口
扩容:初始容量16,负载因子0.75,扩容增量1倍
遍历:1-先获取所有键的Set集合,再遍历(通过键来获取值)2-取出保存好的Entry的Set,再遍历Set即可
实现
HashMap
线程不安全,但是速度最快,最常用
内部采用对象数组存放数据
流程图中绿色标出的部分为JDK8新增的处理逻辑,目的是在Table[i]中的Node节点数量大于8时,通过红黑树提升查找速度。
put执行过程
在使用put的方法时,Map中的table数组会使用hashcode方法来计算写入的Key值到底该数组存储table中什么位置。前提:在实体类中写入hashcode与equals方法
在我们使用get方法的时候也是类似,首先会通过hashcode计算我们需要得到的数据会保存在哪里。如果table[i]的存储的数组只有一个,直接会把该数据得到。如果里面的数据不止一只,那它就会通过遍历的方式,一个一个来遍历,最终得到想要的结果。因为table[i]中存储的是对象数组是链表结构。在jdk8之后就开始不同了,如果你的table[i]中的数组超过了8个,那它就会使用红黑树的方式来存储数据。这样的存储方式会让数据能够更好的遍历,因为不需要一个一个找了,所以速度会加快。前提:要在jdk8之后的版本才有这个功能,在jdk8版本之前都是数组的形式来存储数据的
Table数组中的的Node
链表结构示意图
红黑树示意图
java.util.Mapp=new HashMap<>(); @Before public void befor() { //增加 p.put("1", 1); p.put("2", 2); p.put("3", 3); p.put("4", 4); p.put("5", 5); } @Test public void text01() { //map键不能重复,值可以 p.put("1", 6); //如果键重复则会覆盖 System.out.println(p); } //使用迭代器遍历 @Test public void text02() { //得到键 Iterator i= p.keySet().iterator(); while(i.hasNext()) { String s= i.next(); //通过键输出对应的值 System.out.println(p.get(s)); } } //使用EntrySet遍历 @Test public void text03() { Iterator > i= p.entrySet().iterator(); while(i.hasNext()) { Entry e= i.next(); System.out.println(e.getKey()+e.getValue()); } } //lambda表达式遍历 @Test public void text04() { p.forEach((k,v)->System.out.println(k+v)); } //增加不存在的数据 @Test public void text05() { //如果Map集合里面没有5这个键,则增加 if(!p.containsKey("5")) { p.put("5", 5); } //第二种方法 //缺席,如果4这个键位有则不增加。如果没有则增加这个键位 p.putIfAbsent("4", 4); }
HashTable
线程安全,不太常用(用一把锁锁住所有,性能慢)方法与HashMap差不多
ConcurrentHashMap
线程安全,性能比HashTable高(因为是分段锁,而且还实现了cis接口)方法与HashMap差不多
TreeMap
1 Key值按一定的顺序排序
2 添加或者获取元素比ConcurrentHashMap慢。因为需要维护内部的红黑树,用于保证Key值的顺序
java.util.TreeMapt; //从小到大排序 @Test public void text02() { //自己本身自带的排序 t=new java.util.TreeMap<>(); t.put("5", 5); t.put("4", 4); t.put("3", 3); t.put("2", 2); t.put("1", 1); t.forEach((k,v)->System.out.println(k+":"+v)); } //按key值进行排序 @Test public void text01() { t=new java.util.TreeMap<>(new Comparator () {//Comparator比较器 //当我们在方法时使用了匿名函数,同时在实体类是实现了Comparable。匿名函数的优先级别会更高 @Override public int compare(String a, String b) { //比较 a>b返回正数 a=b 返回0 aSystem.out.println(k+v)); } //排序 @Test public void text04() { TreeSet t=new TreeSet<>(new Comparator () { @Override public int compare(Student a, Student b) { // TODO Auto-generated method stub return b.getSid()-a.getSid();//倒序 } }); t.add(new Student("1", 1)); t.add(new Student("2", 2)); t.add(new Student("3", 3)); t.add(new Student("4", 4)); t.add(new Student("5", 5)); t.forEach(y->System.out.println(y)); } //最后一种方法可以通过在实体类中写入Comparator @Test public void text05() { TreeSet s=new TreeSet<>(); s.add(new Student("1", 1)); s.add(new Student("2", 2)); s.add(new Student("3", 3)); s.add(new Student("4", 4)); s.add(new Student("5", 5)); s.forEach(i->System.out.println(i)); }
linkedHashMap
继承HashMap
linkedHashMap是有序的,而且默认为插入顺序(与你怎么写就怎么输出)但我们需要有序的存储Key或者value是就使用linkedHashMap



