Java常用类库(2)——集合

1.类集可以称为是Java对数据结构的充分实现

2.类集的分类:Collection Map  Iterator 是最大的接口

 

 

3.Collection是单值集合,她又被细分为两个接口list 和 set。

4.Collection中常见的方法:

 

 

 1 public static void main(String [] args){
 2       //创建一个Collection对象,采用多态的的形式
 3       Collection cl = new ArrayList<Interger>();
 4       //向集合中添加元素
 5       cl.add(18);
 6       cl.add(19);
 7       //创建一个Vector对象
 8       Vector<Interger> v = new Vector<Interger>();
 9       //向里面添加元素
10       v.add(13);
11       v.add(14);
12       //像最上面的集合中添加一个集合
13       cl.addAll(v);
14       //查找一个元素是否存在
15       System.out.print(cl.contains(12));//false
16       //判断集合是否为空
17       System.out.print(cl.isEmpty());//false
18       //从集合中删除一个对象remove(Object o);
19       //从集合中删除一组对象remove(Collection<?>c);
20       //判断集合没有指定的集合retainsAll(Collection<?>c);
21       //求出元素的个数
22       int num = cl.size();
23       //以对象的数组形式返回集合的所有内容
24       Interger in = cl.toArray();
25       //equals(Object o);从Object 类中覆写而来
26       //hashCode(Object o);从Object类中覆写而来
27 }

4.list允许重复,set不允许重复。

5.list中常见的方法:

 

 

 1 public static void main(String [] args){
 2       //通过多态创建集合对象
 3       List list = new ArrayList<Interger>();
 4       //在指定位置添加元素
 5       list.add(0,e);
 6       list.add(1,e2);
 7       list.add(2,e3);
 8       //add(int index,Collection<?>c)在指定位置添加一组元素
 9       //根据索引位置取出一组元素
10       cl.get(0);
11       //删除指定位置处的元素
12       cl.remove(1);
13       //修改指定位置处的内容
14       cl.set(2,e);
15       //截取集合,返回子集合
16       cl.subList(1,3);
17 }

5.list的实现类:ArrayList    Vector       LinkedList

5.1)ArrayList类:

1)ArrayList:底层是动态的数组,具有查找,修改块,增加删除慢的特点

2)ArrayList中构造方法:

ArrayList()
构造一个初始容量为10的空列表。
ArrayList​(int initialCapacity)
构造具有指定初始容量的空列表。
ArrayList​(Collection<? extends E> c)
按照集合的迭代器返回的顺序构造一个包含指定集合元素的列表。 

3)ArrayList中常见的方法:

 

 

 4)相应的代码操作如上

5.2)Vector类:Vector类似于ArrayList,但是该类是线程安全的,她的操作类似于Vector.

5.3)   LinkedList类:

1)她的底层是双向链表,可以当作是栈和队列(单向队列,双端队列)来使用。

2)构造方法:

 

 3)常用方法:

 

 

 4)代码的演示如上

 

6.set集合:

1.set继承自Collection ,所以很多方法都和Collection相同。

2.Collection 和 set集合都没有提供获取元素的代码,那set集合如何获取呢

2.1)通过迭代器的方式获取

2.2)通过toArray()方法转换为数组的方式获取

3.set集合不包含重复元素

4.set集合不适合用来存储可变对象(例如person类等),因为set集合的一些子类是无序的,当修改一些值的时候,会导致内存空间错乱

5.set集合接口的实现类:hashSet    TreeSet   

5.1)hashSet集合:

1)底层是散列表(哈希表),她的存储是无序的

2)他的使用方法同set相似

5.2)TreeSet集合:

1)底层的数据结构是二叉树,是有序存储

2)迭代器快速失败:带迭代器在迭代一个集合时,有另一个线程改变了集合的长度,导致于迭代器预期的长度不同,此时会报错

      迭代器安全失败:迭代器迭代的是复制的子集合

3)TreeSet集合是有序打印的:

 1 public static void main(String[] args) {
 2         //创建TreeSet集合
 3         TreeSet<String> data = new TreeSet<String>();
 4         data.add("D");
 5         data.add("C");
 6         data.add("A");
 7         data.add("B");
 8         for(String s:data){
 9             System.out.println(s);
10         }
11     }
12 //结果为:A B C D

4)当TreeSet在比较自定义类型的对象时,系统不认识,要报错,这个时候我们就要让该类型实现Comparable接口,并且从写里面的CompareTo()方法

 1  public static void main(String[] args) {
 2         //创建TreeSet集合
 3         TreeSet<Person> data = new TreeSet<Person>();
 4         Person p1 = new Person("张三",18);
 5         Person p2 = new Person("李四",19);
 6         Person p3 = new Person("王五",20);
 7         //如果两个对象的年龄相同,因为不重复,后者重复的年龄添加失败
 8         data.add(p1);
 9         data.add(p2);
10         data.add(p3);
11 
12         for(Person s:data){
13             System.out.println(s);
14         }
15     }
16     //静态内部类
17     static class Person implements Comparable<Person>{
18 
19         private String name;
20         private int age;
21 
22         @Override
23         public int compareTo(Person o) {
24             //当this小时返回正数,this大返回负数,两个相同时返回0
25             //此时以年龄来比较
26             if(this.age>o.age){
27                 return -1;
28             }else if(this.age<o.age){
29                 return 1;
30             }
31             return 0;
32         }
33 
34         public Person(String name, int age) {
35             this.name = name;
36             this.age = age;
37         }
38 
39         public String getName() {
40             return name;
41         }
42 
43         public void setName(String name) {
44             this.name = name;
45         }
46 
47         public int getAge() {
48             return age;
49         }
50 
51         public void setAge(int age) {
52             this.age = age;
53         }
54 
55         @Override
56         public String toString() {
57             return "Person{" +
58                     "name='" + name + '\'' +
59                     ", age=" + age +
60                     '}';
61         }
62 
63         @Override
64         public boolean equals(Object o) {
65             if (this == o) return true;
66             if (o == null || getClass() != o.getClass()) return false;
67             Person person = (Person) o;
68             return age == person.age &&
69                     Objects.equals(name, person.name);
70         }
71 
72         @Override
73         public int hashCode() {
74             return Objects.hash(name, age);
75         }
76 
77     }

 

6.Map集合:

1.Map接口是存储键值对的,

2.set接口的底层原理也是Map,他只存储一个值,另一个设置了默认值,因为键是不可以重复的,所以set集合不能重复

3.set接口中常用的方法:

1)clear();清空集合

2)keySet();获取Map集合的键,返回一个单独存储键的Set集合

3)get(键);通过迭代获取的键来寻找相应的值

4)put(K key,V value);添加元素,一个键只能对应一个值,当这个键原来有值是,新的值就将会覆盖原来的值,并且返回原来的值,原来没有值就会返回null

4)remove(K key);删除时会返回被删除的值V,这个场景可以用在既要取数据,又要删除的数据的操作中

5)containsKey(Object key);判断键在集合中是否存在

6)containsValue(Object value);判断值在集合中是否存在

7)replace(K key,V value);通过键把原来的值修改掉

8)size();返回键值对的对数

9)values();该方法值获取值,将他返回一个Collection类型的集合

4.Map接口的实现类:hashMap  TreeMap   LinkedMap    hashTable等

1)hashMap:

1.1)是基于哈希表的Map接口的实现

1.2)哈希表的结构:

 

 解释:1.Java中万物皆对象,通过对象调用hashCode()方法得到每个对象的哈希值,将这个对16进行取余,得到一个0-15的数字,将这个数字作为下表,存放到哈希                 数组里面,数组里面是链表,可以存放多个余数相同的对象

            2.哈希表是数组+链表的形式,hashMap集合的默认有16个长度,下表从0到15.,每个空间成为一个哈希桶

            3.哈希桶的默认值为16,当大于散列因子(0.75),即哈希桶的数据存入数量大于桶总数的百分之七十五的时候,会进行自动扩容,长度为原来的两倍,取余长                 度也会相应的改变。

1.3)hashMap集合的put(K key , V value)方法:

 

源码:

 

 

 

 

 2)Map集合的一些常用操作,几乎所有的都是这一套操作流程:

 1 //创建集合对象
 2         HashMap<String ,String> map = new HashMap<>();
 3         //存入值
 4         map.put("key1","锄禾日当午");
 5         map.put("key2","汗滴禾下土");
 6         map.put("key3","谁知盘中餐");
 7         map.put("key4","粒粒皆辛苦");
 8         //调用方法来获取键的集合
 9         Set<String> ss = map.keySet();
10         for(String s:ss){
11             System.out.println(s+"->"+map.get(s));
12         }
13 
14     }
15 //上诉的HashMap可以变换为Map的其他实现类

3)Map集合中不同实现类的差别:

hashTable采用的是排队

TreeMap是有顺序的,根据键排队底层是二叉树

LinkedHashMap与HashMap相似,他弥补了HashMap无序的不住,他底层是哈希表和双向链表,既保证了有序,又保证了查找等操作快

 

5.散列表散列操作

1)HashMap集合的哈希表的初始值要根据实际情况进行合理的赋值,来避免频繁的散列(哈希表的重建)带来的不必要的繁琐的操做

2)散列因子越大,空间利用率越好,查询效果越慢;散列因子越小,空间利用率越小,查询效果越好

 

6.存储自定义对象

1)代码演示:

 1 public static void main(String[] args) {
 2         //当用Map集合存储一个对象的时候,一定要重写hashCode方法,不然底层默认的是Object类的hashCode方法
 3         //创建集合对象
 4         HashMap<Book,String> map = new HashMap<>();
 5         //创建Book对象
 6         Book b1 = new Book("金苹果","讲诉了种植苹果树的艰辛过程");
 7         //添加元素
 8         map.put(b1,"我们人生的第一本书");
 9         //创建Book对象
10         Book b2 = new Book("银苹果","讲诉了种植苹果树的艰辛过程");
11         //添加元素
12         map.put(b1,"我们人生的第二本书");
13         //此时修改b1的属性
14         b1.setName("铜苹果");//将属性改变后,从新计算了一个哈希值,这样通过这个哈希值,我们找不到原来存储的对象了
15         //散列,即重新创建一个数据结构,将原来的数据重新储存到新的哈希表中
16         //此时通过获取值,返回值为null
17         System.out.println(map.get(b1));
18         //创建Book对象
19         Book b3 = new Book("金苹果","讲诉了种植苹果树的艰辛过程");
20         //添加元素
21         map.put(b3,"我们人生的第二本书");
22         //当b3对象和b1内容相同的时候,会去通过equals判断两个对象是否相同,如果相同,则会找到原来的哈希值,找到b1对象的数据
23         //因为是新创建的对象,所以equals比较为false,找不到换来的b1,所以不要改变存储在Map集合中的数据
24         System.out.println(b3);
25 
26 
27     }
28     //静态内部内
29     static class Book{
30 
31         private String name;
32         private String info;
33 
34         public Book(String name, String info) {
35             this.name = name;
36             this.info = info;
37         }
38 
39         public String getName() {
40             return name;
41         }
42 
43         public void setName(String name) {
44             this.name = name;
45         }
46 
47         public String getInfo() {
48             return info;
49         }
50 
51         public void setInfo(String info) {
52             this.info = info;
53         }
54 
55         @Override
56         public String toString() {
57             return "Book{" +
58                     "name='" + name + '\'' +
59                     ", info='" + info + '\'' +
60                     '}';
61         }
62 
63         @Override
64         public boolean equals(Object o) {
65             if (this == o) return true;
66             if (o == null || getClass() != o.getClass()) return false;
67             Book book = (Book) o;
68             return Objects.equals(name, book.name) &&
69                     Objects.equals(info, book.info);
70         }
71 
72         @Override
73         public int hashCode() {
74             return Objects.hash(name, info);
75         }
76 
77 
78     }

 

6.JDK9版本提供的集合新特性:

1)

 

 

 

(已上是Map的方法,List和set类似)

 只有List set Map这三个接口才可以有这个特性,这个特性就是建立特定长度不可变的集合长度,主要用来存储数据少的情况下

2)代码演示:

 1 public static void main(String[] args) {
 2         //演示List
 3         List<String> list = List.of("锄禾日当午", "汗滴禾下土", "谁知盘中餐", "粒粒皆辛苦");
 4         //该集合长度已经定了,不能在使用添加的操作
 5         for(String s:list){
 6             System.out.println(s);
 7         }
 8 
 9         //演示set集合
10         Set<String> set = Set.of("锄禾日当午", "汗滴禾下土", "谁知盘中餐", "粒粒皆辛苦");
11         for(String s:set){
12             System.out.println(s);
13         }
14 
15         //演示Map集合
16         Map<String, String> map = Map.of("老鼠", "爱大米", "我", "爱干饭");
17         Set<String> strings = map.keySet();
18         for(String str:strings){
19             System.out.println(str+"->"+map.get(str));
20         }
21     }

 

 

二:迭代器

1.迭代器有两种:Iterator(用于所有的Collection类集的迭代遍历)和ListIterator(仅用于List集合的遍历)

2.Iterator中的方法:

 

 3.代码演示:

3.1)基本操作

 1 public static void main(String[] args) {
 2         //1.创建一个集合对象
 3         ArrayList<Integer> list = new ArrayList<>();
 4         //向集合里面添加元素
 5         list.add(1);
 6         list.add(2);
 7         list.add(3);
 8         list.add(4);
 9         list.add(5);
10         //调用方法,生成迭代器对象
11         Iterator<Integer> iterator = list.iterator();
12         while(iterator.hasNext()){//判断指针后面是否还有元素,有就迭代
13             Integer next = iterator.next();//移动指针,并且获取当前指针的值
14             System.out.println(next);
15         }
16     }

3.2)演示remove()方法

 1 public static void main(String[] args) {
 2         //1.创建一个集合对象
 3         ArrayList<Integer> list = new ArrayList<>();
 4         //向集合里面添加元素
 5         list.add(1);
 6         list.add(2);
 7         list.add(3);
 8         list.add(4);
 9         list.add(5);
10         //调用方法创建迭代器
11         Iterator<Integer> iterator = list.iterator();
12         //先将指针移到指定位置后才可以删除
13         iterator.next();
14         iterator.remove();
15         System.out.println(list.size());//4
16     }

 

添加的元素添加到next的上一个位置,如图中所示,上诉图是迭代器的工作原理

4.ListIterator中的方法:

 

 4.1)代码演示:

 public static void main(String[] args) {
        //1.创建一个集合对象
        ArrayList<Integer> list = new ArrayList<>();
        //向集合里面添加元素
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        //调用方法创建迭代器
        ListIterator<Integer> iterator = list.listIterator();
        //添加元素
        iterator.add(100);
        //将指针往下移动
        iterator.next();
        iterator.next();
        //将第二个元素设置为200
        iterator.set(200);
        //将指针上移动,遍历整个集合
        iterator.previous();
        iterator.previous();
        //以为添加了一个100,所以还要上移动
        iterator.previous();
        //遍历
        while(iterator.hasNext()){
            System.out.println(iterator.next());;
        }
    }


/*
结果:
100
1
200
3
4
5
*/

 

三:forEach循环(增强for循环)

1.作用范围:数组+Collection集合

2.代码演示:

 1  public static void main(String[] args) {
 2         //1.创建一个集合对象
 3         ArrayList<Integer> list = new ArrayList<>();
 4         //向集合里面添加元素
 5         list.add(1);
 6         list.add(2);
 7         list.add(3);
 8         list.add(4);
 9         list.add(5);
10         //调用方法创建迭代器
11         ListIterator<Integer> iterator = list.listIterator();
12         //添加元素
13         iterator.add(100);
14         //将指针往下移动
15         iterator.next();
16         iterator.next();
17         //将第二个元素设置为200
18         iterator.set(200);
19         //将指针上移动,遍历整个集合
20         iterator.previous();
21         iterator.previous();
22         //以为添加了一个100,所以还要上移动
23         iterator.previous();
24         //遍历
25 //        while(iterator.hasNext()){
26 //            System.out.println(iterator.next());;
27 //        }
28         for(Integer s:list){
29             System.out.println(s);
30         }
31     }

三:总结:

集合同数组一样,都是用来存数据的框框,当我们要存储数据时,通过考虑数据的特点以及他要的操作,选取合适的集合来存储数据,当在操作数据时,对于我们要解决的需求,我们因该考虑该集合中的方法,去查找API文档,如果能找到就直接用,不能找到在考虑其他方法。

 

posted @ 2021-06-08 14:21  白杨树&  阅读(83)  评论(0编辑  收藏  举报