Java基础(10)— 集合框架

集合框架

  • 集合能够看做是一种容器,用来存储对象信息。全部集合类都位于java.util包下,但支持多线程的集合类位于java.util.concurrent包下。java

  • 数组与集合的区别node

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

Collection家族

  • Collection 接口数组

    截图

    序号 接口描述
    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)时,将链表转换为红黑树,这样大大减小了查找时间。异步

      截图

  • 代码表现ide

    public class LinkedListDemo{ 
        public static void main(String[] args) { 
            LinkedList<String> link = new LinkedList<String>(); 
            //添加元素 
            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<String> set = new HashSet<String>();
            //添加元素 
            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<Student> stuSet = new HashSet<Student>(); 
            //存储 
            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<String> set = new LinkedHashSet<String>(); 
            set.add("bbb"); 
            set.add("aaa"); 
            set.add("abc"); 
            set.add("bbc"); 
            Iterator<String> 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<? super T> ) ,将集合中元素按照指定规则排序
    public class CollectionsDemo {
        public static void main(String[] args) {
            ArrayList<Integer> list = new ArrayList<Integer>(); 
            //原来写法 
            //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<? super T> ) ,将集合中元素按照指定规则排序
  • Comparator比较器

    public class CollectionsDemo3 { 
        public static void main(String[] args) { 
            ArrayList<String> list = new ArrayList<String>(); 
            list.add("cba"); 
            list.add("aba");
    		list.add("sba"); 
            list.add("nba"); 
            //排序方法 按照第一个单词的降序 
            Collections.sort(list, new Comparator<String>() {
                @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<Student> list = new ArrayList<Student>(); 
            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<Student>{ 
        .... 
        @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<Student>() { 
    	@Override 
        public int compare(Student o1, Student o2) { 
            return o2.getAge()-o1.getAge();//以学生的年龄降序 
        } 
    });
    /*
    上列代码,效果与上边输出同样
    下列代码,为多规则断定
    */
    Collections.sort(list, new Comparator<Student>() {
        @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的映射

    序号 描述类
    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<Map.Entry<K,V>> entrySet(),获取到Map集合中全部的键值对对象的集合(Set集合)
    public class MapDemo { 
        public static void main(String[] args) { 
            //建立 map对象 
            HashMap<String, String> map = new HashMap<String, String>(); 
            //添加元素到集合 
            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<String, String> map = new HashMap<String,String>(); 
            //添加元素到集合 
            map.put("胡歌", "霍建华"); 
            map.put("郭德纲", "于谦"); 
            map.put("薛之谦", "大张伟"); 
            //获取全部的键 获取键集
            Set<String> 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<String, String> map = new HashMap<String,String>(); 
            // 添加元素到集合 
            map.put("胡歌", "霍建华"); 
            map.put("郭德纲", "于谦"); 
            map.put("薛之谦", "大张伟"); 
            // 获取 全部的 entry对象 
            entrySet Set<Entry<String,String>> entrySet = map.entrySet(); 
            // 遍历获得每个entry对象 
            for (Entry<String, String> 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集合对象。
            Map<Student,String>map = new HashMap<Student,String>(); 
            //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<Student> 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<String> str1=Set.of("a","b","c"); 
            //str1.add("c");这里编译的时候不会错,可是执行的时候会报错,由于是不可变的集合 
            System.out.println(str1); 
            Map<String,Integer> str2=Map.of("a",1,"b",2); 
            System.out.println(str2); 
            List<String> 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)。简单的理解,就是一种相似于咱们生活中树的结构,只不过每一个结点上都最多只能有两个子结点。二叉树是每一个节点最多有两个子树的树结构。顶上的叫根结点,两边被称做"左子树"和"右子树"

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

  • 红黑树的约束

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

相关文章
相关标签/搜索