Java基础(10)— 集合框架

集合框架

  • 集合可以看作是一种容器,用来存储对象信息。所有集合类都位于java.util包下,但支持多线程的集合类位于java.util.concurrent包下。

  • 数组与集合的区别

    • 数组的长度是固定的。集合的长度是可变的
    • 数组中存储的是同一类型的元素,可以存储基本数据类型值。集合存储的都是对象,而且对象的类型可以不一致。在开发中一般当对象多的时候,使用集合进行存储。

Collection家族

  • Collection 接口

    Java基础(10)— 集合框架_第1张图片

    序号 接口描述
    1 Collection 接口
    Collection 是最基本的集合接口。一个 Collection 代表一组 Object ,即 Collection 元素
    Java不提供直接继承Collection的类,只提供继承于它的子接口(如List,Set)
    Collection接口存储一组不唯一,无序的对象
    2 List 接口
    List 是一个有序的 Collection,此接口能够精准的控制每个元素插入的位置,可以通过索引来访问 List 中的元素
    第一个元素索引为0,而且允许有相同的元素
    List 接口存储一组不唯一,有序(插入顺序)的对象
    3 Set 接口
    Set 具有与 Collection 完全一样的接口,只是行为上不同,Set 不保存重复的元素
    4 SortedSet 接口
    继承于 Set 的子接口,但是它保存的是唯一有序的集合
    5 Queue 接口
    Queue 就是队列,队列的特点是先进先出,通常,不允许随机访问元素。
  • Set 与 List 的区别

    • Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可重复的元素
    • Set 检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 <实现类有HashSet,TreeSet>
    • List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变 <实现类有ArrayList,LinkedList,Vector>
  • Collection 实现类(常用集合类)

    序号 类描述
    1 List
    |➡ArrayList
    该类实现了可变大小的数组,为随机访问和遍历元素提供了更好的性能
    线程不安全的(异步),多线程情况下不要使用。
    ArrayList 扩容长度 50%,插入删除效率低。
    底层为数组结构
    2 List
    |➡Vector
    该类与ArrayList 类非常相似
    线程安全的(同步),多线程情况下,该类允许默认扩容长度100%
    底层为数组结构
    3 List/Queue
    |➡LinkedList
    该类没有同步方法,如果多线程同时访问要给List,则必须自己实现访问同步
    解决方法就是创建List时创造一个同步的List = Collections.synchronizedList(newLinkedList(...));
    底层为双向链表结构
    4 Queue
    |➡ArrayQueue
    该类是一个循环队列,继承了AbstractList 抽象类
    底层为数组结构
    5 Set
    |➡HashSet
    该类不允许出现重复元素,不保证集合中元素的顺序,允许包含值为Null的元素,但最多一个
    底层为哈希表结构(一个HashMap实例)由数组+链表/红黑树构成(链表长度大于8切换为红黑树)
    6 Set
    |➡TreeSet
    该类实现排序等功能
    底层为红黑树结构
    7 Set
    |➡HashSet
    |➡LinkedHashSet
    该类不仅保证了元素的唯一,同时元素存放是由顺序的
    底层为链表+哈希表结构
  • 特别说明

    • JDK 1.8之前,哈希表是由 数组+链表 实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。

    • 而 JDK 1.8,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。

      Java基础(10)— 集合框架_第2张图片

  • 代码表现

    public class LinkedListDemo{ 
        public static void main(String[] args) { 
            LinkedList link = new LinkedList(); 
            //添加元素 
            link.addFirst("abc1"); 
            link.addFirst("abc2"); 
            link.addFirst("abc3"); 
            System.out.println(link); 
            // 获取元素 
            System.out.println(link.getFirst()); 
            System.out.println(link.getLast()); 
            // 删除元素 
            System.out.println(link.removeFirst()); 
            System.out.println(link.removeLast()); 
            while (!link.isEmpty()) { 
                //判断集合是否为空 
                System.out.println(link.pop()); //弹出集合中的栈顶元素(弹栈) 
            }
            System.out.println(link); 
        } 
    }
    /*
    输出结果:
        [abc3, abc2, abc1]
        abc3
        abc1
        abc3
        abc1
        abc2
        []
    */
    
    public class HashSetDemo { 
        public static void main(String[] args) { 
            //创建 Set集合 
            HashSet set = new HashSet();
            //添加元素 
            set.add(new String("cba")); 
            set.add("abc"); 
            set.add("bac"); 
            set.add("cba"); 
            //遍历 
            for (String name : set) { 
                System.out.println(name); 
            } 
            System.out.println("==========")
            //创建集合对象 该集合中存储 Student类型对象
            HashSet stuSet = new HashSet(); 
            //存储 
            Student stu = new Student("于谦", 43); 
            stuSet.add(stu); 
            stuSet.add(new Student("郭德纲", 44)); 
            stuSet.add(new Student("于谦", 43)); 
            stuSet.add(new Student("郭麒麟", 23)); 
            stuSet.add(stu); 
            for (Student stu2 : stuSet) { 
                System.out.println(stu2); 
            }
        } 
    }
    /*
    输出结果:
    	cba
    	abc
    	bac
    	==========
    	Student [name=郭德纲, age=44] 
    	Student [name=于谦, age=43] 
    	Student [name=郭麒麟, age=23]
    tips:
    	根据结果我们发现字符串“cba”与Student [name=于谦, age=43]只存储了一个,也就是说重复的元素set集合不存储
    */
    
    public class LinkedHashSetDemo { 
        public static void main(String[] args) { 
            Set set = new LinkedHashSet(); 
            set.add("bbb"); 
            set.add("aaa"); 
            set.add("abc"); 
            set.add("bbc"); 
            Iterator it = set.iterator(); 
            while (it.hasNext()) { 
                System.out.println(it.next()); 
            } 
        } 
    }
    /*
    运行结果
       	bbb
        aaa
        abc
        bbc
    */
    

Collections工具

  • java.utils.Collections 是集合工具类,用来对集合进行操作

    • public static boolean addAll(Collection c, T... elements) ,往集合中添加一些元素
    • public static void shuffle(List list) 打乱顺序 ,打乱集合顺序
    • public static void sort(List list) ,将集合中元素按照默认规则排序
    • public static void sort(List list,Comparator ) ,将集合中元素按照指定规则排序
    public class CollectionsDemo {
        public static void main(String[] args) {
            ArrayList list = new ArrayList(); 
            //原来写法 
            //list.add(12); 
            //list.add(14); 
            //list.add(15); 
            //list.add(1000); 
            //采用工具类 完成 往集合中添加元素 
            Collections.addAll(list, 5, 222, 1,2); 
            System.out.println(list); 
            //排序方法 
            Collections.sort(list); 
            System.out.println(list); 
        } 
    }
    /*
    运行结果: 
        [5, 222, 1, 2] 
        [1, 2, 5, 222]
    */
    
    • public static void sort(List list, Comparator ) ,将集合中元素按照指定规则排序
  • Comparator比较器

    public class CollectionsDemo3 { 
        public static void main(String[] args) { 
            ArrayList list = new ArrayList(); 
            list.add("cba"); 
            list.add("aba");
    		list.add("sba"); 
            list.add("nba"); 
            //排序方法 按照第一个单词的降序 
            Collections.sort(list, new Comparator() {
                @Override public int compare(String o1, String o2) {
                    /*
                        两个对象比较的结果有三种:大于,等于,小于。
                        	如果要按照升序排序,则 o1 小于 o2
                        	如果要按照降序排序,则 o1 小于 o2
                    */
                    return o2.charAt(0) - o1.charAt(0); 
                } 
            }); System.out.println(list); 
        } 
    }
    
    public int compare(String o1, String o2) 
    
    
    • Comparable 强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo方法被称为它的自然比较方法。只能在类中实现compareTo()一次,不能经常修改类的代码实现自己想要的排序。实现此接口的对象列表(和数组)可以通过Collections.sort(和Arrays.sort)进行自动排序,对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。
    • Comparator 强行对某个对象进行整体排序。可以将Comparator 传递给sort方法(如Collections.sort或 Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用Comparator来控制某些数据结构(如有序set或有序映射)的顺序,或者为那些没有自然顺序的对象collection提供排序。
    • 练习例子
    //实体
    public class Student{ 
        private String name; private int age; 
        public Student() { }
        public Student(String name, int age) {
            this.name = name; 
            this.age = age; 
        }
        public String getName() { 
            return name; 
        }
        public void setName(String name) {
            this.name = name; 
        }
        public int getAge() {
            return age; 
        }
        public void setAge(int age) { 
            this.age = age; 
        }
        @Override 
        public String toString() {
            return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; 
        } 
    }
    //测试类
    public class Demo { 
        public static void main(String[] args) { 
            // 创建四个学生对象 存储到集合中 
            ArrayList list = new ArrayList(); 
            list.add(new Student("rose",18)); 
            list.add(new Student("jack",16)); 
            list.add(new Student("abc",16)); 
            list.add(new Student("ace",17)); 
            list.add(new Student("mark",16)); 
            /*
            让学生 按照年龄排序 升序 
            */ 
            // Collections.sort(list);//要求 该list中元素类型 必须实现比较器Comparable接口 
            for (Student student : list) { 
                System.out.println(student); 
            } 
        } 
    }
    /*
    发现
    	当我们调用Collections.sort()方法的时候程序报错
    原因
    	如果想要集合中的元素完成排序,那么必须要实现比较器Comparable接口、
    */
    public class Student implements Comparable{ 
        .... 
        @Override 
        public int compareTo(Student o) { 
            return this.age-o.age;//升序 
        } 
    }
    /*
    运行结果
    	Student{name='jack', age=16} 
    	Student{name='abc', age=16} 
    	Student{name='mark', age=16} 
    	Student{name='ace', age=17} 
    	Student{name='rose', age=18}
    */
    
    • 拓展,如果想在方法中独立使用定义规则可以采用Collections.sort(List list,Comparetor c)
    Collections.sort(list, new Comparator() { 
    	@Override 
        public int compare(Student o1, Student o2) { 
            return o2.getAge()-o1.getAge();//以学生的年龄降序 
        } 
    });
    /*
    上列代码,效果与上边输出一样
    下列代码,为多规则判定
    */
    Collections.sort(list, new Comparator() {
        @Override 
        public int compare(Student o1, Student o2) { 
            // 年龄降序 
            int result = o2.getAge()-o1.getAge();
            //年龄降序 
            if(result==0){//第一个规则判断完了 下一个规则 姓名的首字母 升序 
                result = o1.getName().charAt(0)-o2.getName().charAt(0); 
            }
            return result; 
        } 
    });
    

Map家族

  • Map接口,存储一组键值对对象,提供key/value的映射

    Java基础(10)— 集合框架_第3张图片

    序号 描述类
    1 Map
    |➡HashMap
    该类是一个散列表,它存储的内容是键值对(key/value)映射
    根据键的HashCode值存储数据,具有很快的访问速度,最多记录一条为Null的键,不支持线程同步
    底层为哈希表结构(数组+链表/红黑树)
    2 Map
    |➡HashMap
    |➡LinkedHashMap
    底层为 链表 + 哈希表
  • 常用方法

    • public V put(K key, V value),把指定的键与指定的值添加到Map集合中
    • public V remove(Object key),把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的
    • public V get(Object key) ,根据指定的键在Map集合中获取对应的值
    • public Set keySet(),获取Map集合中所有的键,存储到Set集合中
    • public Set> entrySet(),获取到Map集合中所有的键值对对象的集合(Set集合)
    public class MapDemo { 
        public static void main(String[] args) { 
            //创建 map对象 
            HashMap map = new HashMap(); 
            //添加元素到集合 
            map.put("黄晓明", "杨颖"); 
            map.put("文章", "马伊琍");
            map.put("邓超", "孙俪"); 
            System.out.println(map); 
            //String remove(String key)
            System.out.println(map.remove("邓超")); 
            System.out.println(map); 
            // 想要查看 黄晓明的媳妇 是谁 
            System.out.println(map.get("黄晓明")); 
            System.out.println(map.get("邓超"));
        }
    }
    /*
    tips: 
    使用put方法时,若指定的键(key)在集合中没有,则没有这个键对应的值,返回null,并把指定的键值添加到集合中
    若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值
    */
    
  • Map遍历键找值

    public class MapDemo01 { 
        /*
            1.获取Map中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键。方法提示: keyset() 
            2.遍历键的Set集合,得到每一个键。 
            3.根据键,获取键所对应的值。方法提示: get(K key) 
        */
        public static void main(String[] args) { 
            //创建Map集合对象 
            HashMap map = new HashMap(); 
            //添加元素到集合 
            map.put("胡歌", "霍建华"); 
            map.put("郭德纲", "于谦"); 
            map.put("薛之谦", "大张伟"); 
            //获取所有的键 获取键集
            Set keys = map.keySet();
    		// 遍历键集 得到 每一个键 
            for (String key : keys) { 
                //key 就是键 //获取对应值 
                String value = map.get(key); 
                System.out.println(key+"的CP是:"+value);
            }
        } 
    }
    
  • Entry键值对对象以及遍历

    /*
    Map中存放的是两种对象 key(键)/value(值),它们在在Map中是一一对应关系。一组K/V又称做Map中的一个Entry(项),Entry将键值对的对应关系封装成了对象,即键值对对象。这样我们在遍历Map集合时,就可以从每一个键值对(Entry)对象中获取对应的键与对应的值。
    方法:
    	public K getKey() :获取Entry对象中的键。 
    	public V getValue() :获取Entry对象中的值。
    操作步骤:
    	1. 获取Map集合中,所有的键值对(Entry)对象,以Set集合形式返回。方法提示: map.entrySet() 。 
    	2. 遍历包含键值对(Entry)对象的Set集合,得到每一个键值对(Entry)对象。
    */
    public class MapDemo02 { 
        public static void main(String[] args) { 
            // 创建Map集合对象 
            HashMap map = new HashMap(); 
            // 添加元素到集合 
            map.put("胡歌", "霍建华"); 
            map.put("郭德纲", "于谦"); 
            map.put("薛之谦", "大张伟"); 
            // 获取 所有的 entry对象 
            entrySet Set> entrySet = map.entrySet(); 
            // 遍历得到每一个entry对象 
            for (Entry entry : entrySet) { 
                // 解析 
                String key = entry.getKey(); 
                String value = entry.getValue(); 
                System.out.println(key+"的CP是:"+value); 
            } 
        }
    }
    /*
    tips:Map集合不能直接使用迭代器或者foreach进行遍历。但是转成Set之后就可以使用了。
    */
    
  • HashMap存储自定义类型键值,使用map.keySet()方法

    /*
    每位学生(姓名,年龄)都有自己的家庭住址。则将学生对象和家庭住址存储到 map集合中。学生作为键, 家庭住址作为值
    */
    public class Student {
        private String name; 
        private int age; 
        public Student() { }
        public Student(String name, int age) { 
            this.name = name; 
            this.age = age; 
        }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public int getAge() { return age; }
        public void setAge(int age) { this.age = age; } 
        
        public boolean equals(Object o) { 
            if (this == o) 
                return true; 
            if (o == null || getClass() != o.getClass()) 
                return false; 
            Student student = (Student) o; 
            return age == student.age && Objects.equals(name, student.name); 
        }
        @Override 
        public int hashCode() { 
            return Objects.hash(name, age); 
        }
    }
    /*map.keySet()方法*/
    public class HashMapTest { 
        public static void main(String[] args) { 
            //1,创建Hashmap集合对象。
            Mapmap = new HashMap(); 
            //2,添加元素。
            map.put(newStudent("lisi",28), "上海"); 
            map.put(newStudent("wangwu",22), "北京"); 
            map.put(newStudent("zhaoliu",24), "成都");
            map.put(newStudent("zhouqi",25), "广州");
        	map.put(newStudent("wangwu",22), "南京"); 
            //3,取出元素。键找值方式 
            Set keySet = map.keySet(); 
            for(Student key: keySet){ 
                Stringvalue = map.get(key);
                System.out.println(key.toString()+"....."+value);
            } 
        } 
    }
    
  • Java 9 ,添加了几重集合工厂方法,更方便创建少量元素的集合

    public class HelloJDK9 { 
        public static void main(String[] args) { 
            Set str1=Set.of("a","b","c"); 
            //str1.add("c");这里编译的时候不会错,但是执行的时候会报错,因为是不可变的集合 
            System.out.println(str1); 
            Map str2=Map.of("a",1,"b",2); 
            System.out.println(str2); 
            List str3=List.of("a","b"); 
            System.out.println(str3); 
        } 
    }
    /*
    两点注意:
        1.of()方法只是Map,List,Set这三个接口的静态方法,其父类接口和子类实现并没有这类方法,比如 HashSet,ArrayList等待; 
        2.返回的集合是不可变的;
    */
    

常见的数据结构

数据存储的常用结构有:栈、队列、数组、链表和红黑树。我们分别来了解一下:

  • 栈(stack) ,又称堆栈,它是运算受限的线性表,其限制是仅允许在标的一端进行插入和删除操作,不允许在其他任何位置进行添加、查找、删除等操作。

  • 简单的说,采用该结构的集合,对元素的存取有如下的特点

    • 先进后出(即,存进去的元素,要在后它后面的元素依次取出后,才能取出该元素)。例如,子弹压进弹夹,先压进去的子弹在下面,后压进去的子弹在上面,当开枪时,先弹出上面的子弹,然后才能弹出下面的子弹。
    • 栈的入口、出口的都是栈的顶端位置
  • 这里两个名词需要注意

    • 压栈,就是存元素。即,把元素存储到栈的顶端位置,栈中已有元素依次向栈底方向移动一个位置。
    • 弹栈,就是取元素。即,把栈的顶端位置元素取出,栈中已有元素依次向栈顶方向移动一个位置。

队列

  • 队列(queue),简称队,它同堆栈一样,也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而在表的另一端进行删除。
  • 简单的说,采用该结构的集合,对元素的存取有如下的特点
    • 先进先出(即,存进去的元素,要在后它前面的元素依次取出后,才能取出该元素)。例如,小火车过山洞,车头先进去,车尾后进去;车头先出来,车尾后出来。
    • 队列的入口、出口各占一侧

数组

  • 数组(Array),是有序的元素序列,数组是在内存中开辟一段连续的空间,并在此空间存放元素。就像是一排出租屋,有100个房间,从001到100每个房间都有固定编号,通过编号就可以快速找到租房子的人。

  • 简单的说,采用该结构的集合,对元素的存取有如下的特点

    • 查找元素快:通过索引,可以快速访问指定位置的元素
    • 增删元素慢,指定索引位置增加元素 需要创建一个新数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引,复制到新数组对应索引的位置。指定索引位置删除元素,需要创建一个新数组,把原数组元素根据索引,复制到新数组对应索引的位置,原数组中指定索引位置元素不复制到新数组中

链表

  • 链表(linked list),由一系列结点node组成(链表中每一个元素称为结点),结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。我们常说的链表结构有单向链表与双向链表,那么这里给大家介绍的是单向链表。

  • 简单的说,采用该结构的集合,对元素的存取有如下的特点

    • 多个结点之间,通过地址进行连接。例如,多个人手拉手,每个人使用自己的右手拉住下个人的左手,依次类推,这样多个人就连在一起了。
    • 查找元素慢,想查找某个元素,需要通过连接的节点,依次向后查找指定元素
    • 增删元素快,增加元素,只需要修改连接下个元素的地址即可。删除元素,只需要修改连接下个元素的地址即可

红黑树

  • 二叉树(binary tree) 是每个结点不超过2的有序树(tree)。简单的理解,就是一种类似于我们生活中树的结构,只不过每个结点上都最多只能有两个子结点。二叉树是每个节点最多有两个子树的树结构。顶上的叫根结点,两边被称作"左子树"和"右子树"

  • 我们要说的是二叉树的一种比较有意思的叫做红黑树,红黑树本身就是一颗二叉查找树,将节点插入后,该树仍然是一颗二叉查找树。也就意味着,树的键值仍然是有序的

  • 红黑树的约束

    • 节点可以是红色的或者黑色的
    • 根节点是黑色的
    • 叶子节点(特指空节点)是黑色的
    • 每个红色节点的子节点都是黑色的
    • 任何一个节点到其每一个叶子节点的所有路径上黑色节点数相同
  • 红黑树的特点,速度特别快,趋近平衡树,查找叶子元素最少和最多次数不多于二倍

你可能感兴趣的:(Java基础(10)— 集合框架)