美文网首页
05-Java基础-集合框架& List & Map

05-Java基础-集合框架& List & Map

作者: xiaohan_zhang | 来源:发表于2017-09-04 20:54 被阅读0次

    集合框架、generic泛型、List、Set、Map、Collections类

    集合框架

    数组和集合的区别:
    1.数组既可以存储基本数据类型,又可以存储引用数据类型,基本数据类型存储的是值,引用数据类型存储的是地址值;
    集合只能存储引用数据类型(对象)集合中也可以存储基本数据类型,但是在存储的时候会自动装箱变成对象;
    2.数组长度是固定的,不能自动增长;
    集合的长度的是可变的,可以根据元素的增加而增长;

    数组和集合什么时候用?
    1.如果元素个数是固定的推荐用数组;
    2.如果元素个数不是固定的推荐用集合;


    集合框架体系

    Set和List的区别

    1. Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。
    2. Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 <实现类有HashSet,TreeSet>。
    3. List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变 <实现类有ArrayList,LinkedList,Vector> 。
    • Collection类
      Collection 是最基本的集合接口,一个 Collection 代表一组 Object,即 Collection 的元素, Java不提供直接继承自Collection的类,只提供继承于的子接口(如List和set)。
    boolean add(E e)                // 添加指定元素
    boolean remove(Object o)        // 删除指定元素
    void clear()                    //清空集合
    boolean contains(Object o)      // 是否包含指定元素
    boolean isEmpty()               // 是否为空
    int size()                      //获取元素个数
    toArray()                       // 把集合转成数组
    boolean addAll(Collection c)    // c1.addAll(c2) 把c2中元素添加到c1中
    boolean removeAll(Collection c) // c1.removeAll(c2)  删除c1中c1、c2的交集
    boolean containsAll(Collection c) // c1.containsAll(c2) c1是否包含c2全部元素
    boolean retainAll(Collection c) // c1.retainAll(c2) 取交集,并将交集赋值给c1,如果c1改变了,返回true,否则返回false。(如果c1是c2的子集,返回false)
    
    • 集合遍历
    List<String> list = new ArrayList<String>();
    list.add("Hello");
    list.add("World");
    list.add("HAHAHAHA");
    //第一种遍历方法使用foreach遍历List
    for(String str:list){            //也可以改写for(int i=0;i<list.size();i++)这种形式
        System.out.println(str);
    }
    
    //第二种遍历,把链表变为数组相关的内容进行遍历
    String[]strArray = new String[list.size()];
    list.toArray(strArray);
    for(int i=0;i<strArray.length;i++) //这里也可以改写为 foreach(String str:strArray)这种形式
    {
        System.out.println(strArray[i]);
    }
    
    //第三种遍历 使用迭代器进行相关遍历
    Iterator<String> ite = list.iterator();
    while(ite.hasNext())//判断下一个元素之后有值
    {
        System.out.println(ite.next());
    }
    
    • ArrayList
    ArrayList arrayList = new ArrayList();
    for (int i = 0; i < 10; i++) {
         //添加元素
         arrayList.add(i);
     }
    // 移除下标为1的元素 并将删除的元素返回
    arrayList.remove(1);
    
    // 移除指定元素 并将删除的元素返回
    arrayList.remove("A");
    
    // 返回指定元素的最小下标
    arrayList.indexOf(3);
    
    // 下标 0 - 3的元素
    arrayList.subList(0, 3);
    
    // 数组中元素个数
    arrayList.size();
    
    // 替换指定下标元素
    arrayList.set(0, "V");
    
    // 并发修改异常产生的原因及解决方案
    List list = new ArrayList();
    list.add("a");
    list.add("b");
    list.add("world");
    list.add("d");
    list.add("e");
    
    /*Iterator it = list.iterator();
      while (it.hasNext()) {
          String str = (String) it.next();
           if (str.equals("world")) {
                list.add("javaee");            //这里会抛出ConcurrentModificationException并发修改异常
          }
     }*/
    ListIterator lit = list.listIterator();        //如果想在遍历的过程中添加元素,可以用ListIterator中的add方法
            while (lit.hasNext()) {
                String str = (String) lit.next();
                if (str.equals("world")) {
                    lit.add("javaee");
                    //list.add("javaee");
                }
            }
    
    • ListIterator

    boolean hasNext()     是否有下一个
    boolean hasPrevious() 是否有前一个
    Object next()      返回下一个元素
    Object previous();   返回上一个元素

    • Vector
    // 添加
    Vector vector = new Vector();
    vector.add("A");
    vector.add(2);
    vector.add(0, "C");
    System.out.println(vector); // [C, A, 2]
    
    Vector vector1 = new Vector(vector);
    System.out.println(vector1); // [C, A, 2]
    
    Vector vector2 = new Vector();
    vector2.add("R");
    vector2.addAll(vector); // 将vector中的所有元素添加到vector2中
    vector2.add(vector); // 将vector添加到vector2中
    System.out.println(vector2); // [R, C, A, 2, [C, A, 2]]
    
    // 删除
    vector2.remove(0); // 删除指定位置的元素
    System.out.println(vector2); // [C, A, 2, [C, A, 2]]
    
    vector2.remove("A"); // 删除指定元素的第一个匹配项,如果不包含该元素,则元素保持不变。
    System.out.println(vector2); // [C, 2, [C, A, 2]]
    
    vector2.removeAll(vector); // 移除包含在 vector 中的所有元素。
    System.out.println(vector2); // [[C, A, 2]]
    
    // 修改
    System.out.println(vector); // [C, A, 2]
    vector.set(0, "first");
    System.out.println(vector); // [first, A, 2]
    
    // 查询
    vector.size(); // 返回vector中有几个元素
    vector.isEmpty(); // vector是否为空
    vector.get(1); // 查找指定索引位置的元素
    vector.toArray(); // 将vector对象转换为数组
    
    • LinkedList
      实现单向队列和双向队列的接口,自身提高了栈操作的方法,链表操作的方法。LinkedList不擅长查询,尽量不要用index。
    LinkedList linkedList = new LinkedList();
    for (int i = 0; i < 10; i ++) {
         linkedList.add(i);
    }
    
    // 链表的第一个元素
    linkedList.getFirst();
    // 链表最后一个元素
    linkedList.getLast();
    
    // 移除
    linkedList.remove(0);
    linkedList.removeFirst();
    linkedList.removeLast();
    
    // 如果不指定索引的话,元素将被添加到链表的最后.
    linkedList.add(1, 0);
    linkedList.addFirst("A");
    linkedList.addLast("B");
    
    // 获取元素下标
    linkedList.indexOf(0);
    
    // 替换指定下标元素
    linkedList.set(0, "C");
    
    • List的三个子类的特点
    • ArrayList:
      底层数据结构是数组,查询快,增删慢。
      线程不安全,效率高。
    • Vector:
      底层数据结构是数组,查询快,增删慢。
      线程安全,效率低。
      Vector相对ArrayList查询慢(线程安全的)
      Vector相对LinkedList增删慢(数组结构)
    • LinkedList:
      底层数据结构是链表,查询慢,增删快。
      线程不安全,效率高。

    查询多用ArrayList
    增删多用LinkedList
    如果都多ArrayList

    generic泛型

    泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
    泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

    • 三种迭代的能否删除
      普通for循环,可以删除,但是索引要--
      迭代器,可以删除,但是必须使用迭代器自身的remove方法,否则会出现并发修改异常
      增强for循环不能删除
    ArrayList<String> arrayList = new ArrayList<>();
    arrayList.add("a");
    arrayList.add("b");
    arrayList.add("b");
    arrayList.add("b");
    arrayList.add("c");
    
    // 普通for循环删除元素
    for (int i = 0; i < arrayList.size(); i++) {
         if ("b".equals(arrayList.get(i))){
             arrayList.remove(i);
             i --;
         }
    }
    
    // 迭代器删除
    // 方式一
    Iterator<String> iterator = arrayList.iterator();
    while (iterator.hasNext()){
         if ("b".equals(iterator.next())){
             iterator.remove();
         }
    }
    System.out.println(arrayList);
    // 方式二
    for (Iterator<String> iterator1 = arrayList.iterator(); iterator1.hasNext();){
         if ("b".equals(iterator1.next())){
             iterator1.remove();
         }
    }
    System.out.println(arrayList);
    
    // 增强for循环(for - each)不能删除,只能遍历
    
    • 可变参数
      这里的变量其实是一个数组.
      如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个.

    格式:
    修饰符 返回值类型 方法名(数据类型… 变量名){}

    int[] a = {11, 22, 33, 44};
    test1(a);
    test(a);
    test(1,2,3,4);
    private static void test1(int[] arr){
         for (int i = 0; i < arr.length; i++) {
             System.out.println(arr[i]);
         }
    }
    
    private static void test(int ... arr){
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
     }
    
    • Arrays工具类的asList()
    // 数组转换为List,不能增删元素,可以使用集合的其他方法
    String[] arr = {"a", "b", "c"};
    List<String> list = Arrays.asList(arr); 
    
    Integer[] arrs = {1,2,3};
    List<Integer> list2 = Arrays.asList(arrs);
    
    // 基本数据类型数组 转 List时,将整个数组作为一个对象存入List
    int[] arra = {1,2,3,4};
    List<int[]> list1 = Arrays.asList(arra);
    
    • List 转数组
    ArrayList<String> arrayList = new ArrayList<>();
    arrayList.add("a");
    arrayList.add("b");
    arrayList.add("c");
    // 当List转数组时,数组长度如果 <= List.size() ,转换后的数组长度等于List的大小
    // 数组长度如果 > List.size() ,分配的数组长度就与指定的长度一样,会多几个null元素
    String[] arr = arrayList.toArray(new String[0]);
    for (int i = 0; i < arr.length; i++) {
         System.out.println(arr[i]);
    }
    
    Set
    • HashSet
      一个按着Hash算法来存储集合中的元素,其元素值可以是NULL。无序的,不能重复存储。
    HashSet<String> set = new HashSet<String>();
    // add(value)方法,可以向set中添加一个元素
    set.add("AA");
    set.add("BB");
    set.add("CC");
    set.add(null);
    
    // addAll方法,可以将一个集合整体加入到set中
    HashSet<String> sets = new HashSet<String>();
    sets.addAll(set);
    
    // remove方法,可以删除指定的一个元素。
    set.remove("BB");
    
    // removeAll方法,可以从set中批量删除一部分数据。
    sets.removeAll(set);
    
    // clear方法,可以快速清空整个set。
    sets.clear();
    
    // size方法,获取set中元素的个数
    set.size();
    
    // isEmpty方法,判断set对象是否为空
    set.isEmpty();
    

    HashSet存储自定义对象,保证元素唯一性方法:
    重写hashCode()和equals()方法:
    编辑区 右键 Generate(Command + N),选择equals()and hashCode()

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Animal)) return false;
        Animal animal = (Animal) o;
        return age == animal.age && Objects.equals(name, animal.name);
    }
    
    @Override
    public int hashCode() {
    
       return Objects.hash(name, age);
    }
    
    • LinkedHashSet
      底层是链表实现的,是set集合中唯一一个能保证怎么存就怎么取的集合对象.
      因为是HashSet的子类,所以也是保证元素唯一的,与HashSet的原理一样.
      允许null元素,并支持所有可选的Set操作。
      像HashSet一样,LinkedHashSet不是线程安全的,所以多个线程的访问必须通过外部机制(如synchronizedSet(Set))进行同步。

    • TreeSet
      TreeSet集合是用来对象元素进行排序的,同样他也可以保证元素的唯一。

    • 当compareTo方法返回0的时候集合中只有一个元素
    • 当compareTo方法返回正数的时候集合会怎么存就怎么取
    • 当compareTo方法返回负数的时候集合会倒序存储

    使用方式
    1.自然顺序(Comparable)
    TreeSet类的add()方法中会把存入的对象提升为Comparable类型
    调用对象的compareTo()方法和集合中的对象比较
    根据compareTo()方法返回的结果进行存储

    public class Person implements Comparable<Person>{
        private String name;
        private int age;
        @Override
        public int compareTo(Person o) {
            int length = this.name.length() - o.name.length();              //比较长度为主要条件
            int num = length == 0 ? this.name.compareTo(o.name) : length;   //比较内容为次要条件
            return num == 0 ? this.age - o.age : num;
        }
    }
    

    2.比较器顺序(Comparator)
    创建TreeSet的时候可以制定 一个Comparator
    如果传入了Comparator的子类对象, 那么TreeSet就会按照比较器中的顺序排序
    add()方法内部会自动调用Comparator接口中compare()方法排序
    调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数

    两种方式的区别
    TreeSet构造函数什么都不传, 默认按照类中Comparable的顺序(没有就报错ClassCastException)
    TreeSet如果传入Comparator, 就优先按照Comparator

    • Map
      将键映射到值的对象
      一个映射不能包含重复的键
      每个键最多只能映射到一个值
    Map<String, Object> map = new HashMap<>();
    map.put("key1", "value1");  // 如果存入的key存在,将被覆盖的值返回
    map.put("key2", "value2");
    map.put("key3", "value3");
    map.put("key4", "value4");
    System.out.println(map); // {key1=value1, key2=value2, key3=value3, key4=value4}
    
    // Removes all elements from this Map
    // map.clear();
    // System.out.println(map); // {}
    
    // Map中是否包含指定的key
    map.containsKey("key1")
    
    // Map中是否包含指定的value
    map.containsValue("value1");
    
    // Map中所有映射集合
    map.entrySet(); // [key1=value1, key2=value2, key3=value3, key4=value4]
    
    // 根据key获取元素
    map.get("key2");
    
    // 是否为空
    map.isEmpty();
    
    // key的集合
    map.keySet();
    
    // values集合
    map.values();
    
    // 移除key对应元素  返回值为删除的值
    map.remove("key1"); 
    
    // 集合元素个数
    map.size();
    
    • 遍历HashMap
    // 方式一
    for (String key : map.keySet()) {
         System.out.println(map.get(key));
     }
    
    // 方式二 比方式一节约资源
    for (Map.Entry<String, Integer> en :  map.entrySet()) {
        String key = en.getKey();
        Integer value = en.getValue();
        System.out.println("key = " + key + ", value = " + value);
    }
    
    Collections类
    ArrayList<String> arrayList = new ArrayList<>();
    arrayList.add("a");
    arrayList.add("d");
    arrayList.add("c");
    arrayList.add("b");
    // 排序
    Collections.sort(arrayList);
    System.out.println(arrayList);
    
    // 二分法查找 返回下标 不存在返回负的插入点-1(负数)
    int i = Collections.binarySearch(arrayList, "c");
    System.out.println(i);
    
    // 获取最大值
    Collections.max(arrayList);
    // 获取最小值
    Collections.min(arrayList);
    
    // 集合反转
    Collections.reverse(arrayList);
    
    // 随机置换顺序
    Collections.shuffle(arrayList);
    
    • 泛型固定下边界
      ?super E
    • 泛型固定上边界
      ?extend E

    相关文章

      网友评论

          本文标题:05-Java基础-集合框架& List & Map

          本文链接:https://www.haomeiwen.com/subject/qotyjxtx.html