Java集合

集合与数组

  • 数组
    1. 长度开始时必须指定,而且一旦指定,不能更改
    2. 保存的必须是同一类型的元素
    3. 数组的增加/删除元素操作比较麻烦
  • 集合
    1. 可以动态保存任意多个对象
    2. 提供了一系列方便操作对象的方法,使用集合添加/删除元素更加简洁明了
    3. Collection接口有两个重要的子接口(List、Set),它们的实现子类都是单列集合
    4. Map接口的实现子类都是双列集合 K-V

Collection接口

Collection接口实现类的特点

  1. Collection实现子类可以存放多个元素,每个元素可以是Objcet
  2. 有些Collection的实现类可以存放重复的元素,有些则不可以
  3. 有些Collection的实现类(List)是有序(存放和取出顺序一致)的,有些(Set)则不是
  4. Collection接口没有直接的实现子类,是通过它的子接口List和Set来实现的
  • 常用方法

    public static void main(String[] args) {
        List list = new ArrayList();
    
        //add 添加单个元素
        list.add("jack");
        list.add(10);//list.add(new Integer(10))
        list.add(true);
        System.out.println("list="+list);
    
        //remove 删除指定元素
        list.remove(0);
        list.remove(true);
        System.out.println("list="+list);
    
        //contains 判断元素是否存在
        System.out.println(list.contains(10));
    
        //size 获取元素个数
        System.out.println(list.size());
    
        //isEmpty 判断是否为空
        System.out.println(list.isEmpty());
    
        //clear 清空
        list.clear();
        System.out.println("list="+list);
    
        //addAll 添加多个元素
        ArrayList arrayList = new ArrayList();
        arrayList.add("歪比歪比");
        arrayList.add("歪比巴卜");
        list.addAll(arrayList);
        System.out.println("list="+list);
    
        //containsAll 判断多个元素是否存在
        System.out.println(list.containsAll(arrayList));
    
        //removeAll 删除多个元素
        list.add("玛卡巴卡");
        list.removeAll(arrayList);
        System.out.println("list="+list);
    
    }
    

Collection接口遍历元素方式1 Iterator(迭代器)

  1. Iterator对象成为迭代器,主要用于遍历Collection集合中的元素
  2. 所有实现了Collection接口的集合类都有一个Iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器
  3. Iterator仅用于遍历集合,Iterator本身并不存放对象
  4. next()作用:1.下移 2.将下移后集合位置上的元素返回
public class CollectionIterator {
    public static void main(String[] args) {
        Collection col = new ArrayList();

        col.add(new Book("三国演义","罗贯中",10.5));
        col.add(new Book("小李飞刀","古龙",5.1));
        col.add(new Book("红楼梦","曹雪芹",30.2));

        //System.out.println("col=" + col);
        //希望能够遍历 col集合
        //1.先得到 col 对应的迭代器
        Iterator iterator = col.iterator();
        //2.使用while循环遍历
        //ctrl + j 显示所有快捷键
        //idea 使用输入itit可快捷生成该循环
        while (iterator.hasNext()){//判断后面是否还有数据
            //返回下一个元素,类型是Object
            Object next = iterator.next();
            System.out.println("next=" + next);
        }
        //3.当退出while循环后,iterator迭代器指向最后一个元素
        //4.如果希望再次遍历,需要重置迭代器
        iterator = col.iterator();
    }
}

class Book{
    private String name;
    private String author;
    private double price;

    public Book(String name, String author, double price) {
        this.name = name;
        this.author = author;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                '}';
    }
}

Collection接口遍历元素方式2 增强for循环

  • 增强for循环可以替代iterator迭代器;增强for循环就是简化版iterator,本质一样,只能用于遍历集合或数组
public static void main(String[] args) {
    Collection col = new ArrayList();

    col.add(new Book("三国演义","罗贯中",10.5));
    col.add(new Book("小李飞刀","古龙",5.1));
    col.add(new Book("红楼梦","曹雪芹",30.2));

    //增强for底层仍是迭代器
    //idea快捷键 I
    for (Object book : col){//不加泛型默认Object
        System.out.println("book=" + col);
    }
}

List接口

  • List接口基本介绍

    1. List接口是Collection接口的子接口

    2. List集合类中元素是有序的(即添加顺序和取出顺序一致)、且可重复

    3. List集合中的每个元素都有其对应的顺序索引

      public static void main(String[] args) {
          //1.List集合类中元素是有序的(即添加顺序和取出顺序一致)、且可重复
          List list = new ArrayList();
          list.add("jack");
          list.add("tom");
          list.add("mary");
          list.add("hsp");
          list.add("tom");
          System.out.println("list="+list);
      
          //List集合中的每个元素都有其对应的顺序索引
          System.out.println(list.get(3));
      
      }
      
    4. List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素

    5. List常用接口:ArrayList、LinkedList、Vector

  • List常用方法

    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("歪比歪比");
        list.add("歪比巴卜");
    
        //插入单个元素
        list.add(1,"DCBC");
        System.out.println("list="+list);
    
        //插入多个元素
        List list2 = new ArrayList();
        list2.add("jack");
        list2.add("tom");
        list.addAll(1,list2);
        System.out.println("list="+list);
    
        //返回某个元素在集合中首次出现的位置
        System.out.println(list.indexOf("tom"));
    
        //返回某个元素在集合中最后出现的位置
        list.add("tom");
        System.out.println(list.lastIndexOf("tom"));
    
        //删除指定位置的元素并返回此元素
        System.out.println(list.remove(0));
    
        //设置指定位置的元素
        list.set(1,"mary");
        System.out.println("list="+list);
    
        //返回从起始位置到末尾位置的子集合 前闭后开
        List list3 = list.subList(0,3);
        System.out.println("list="+list);
        System.out.println("list3="+list3);
    }
    

List接口实现子类

ArrayList

  • ArrayList注意事项

    1. ArrayList可以加入一个或多个null
    2. ArrayList是由数组来实现数据存储的
    3. ArrayList基本等同于Vector,但ArrayList线程不安全(执行效率高),在多线程中不建议使用ArrayList
  • ArrayList扩容机制

    1. ArrayList中维护了一个Object类型的数组elementData

      transient Object[] elementData;//被transient 修饰的属性不会被序列化

    2. 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第1次添加时扩容elementData为10;如果需要再次扩容,则扩容elementData为原来的1.5倍(新容量等于旧容量加上旧容量的一半)

    3. 如果使用的是指定大小的构造器,则初始elementData容量为指定大小;如果需要扩容,则扩容elementData为原来的1.5倍

Vector

  • Vector注意事项

    1. Vector是线程同步的,即线程安全,Vector类的操作方法带有synchronized。在开发中,需要线程同步安全时,考虑使用Vector
  • Vector扩容机制

    底层结构线程安全(同步)效率扩容倍数
    ArrayList可变数组不安全,效率高无参:第一次10;从第二次开始按1.5倍扩容
    有参:1.5倍扩容
    Vector可变数组安全,效率不高无参:第一次10;从第二次开始按2倍扩容
    有参:2倍扩容

LinkedList

  • LinkedList注意事项
    1. LinkedList底层实现了双向链表和双端队列特点
    2. 可以添加任意元素(元素可以重复),包括null
    3. 线程不安全,没有实现同步
  • LinkedList底层操作机制
    1. LinkedList底层维护了一个双向链表
    2. LinkedList中维护了两个属性first和last分别指向首节点和尾节点
    3. 每个节点(Node对象)里面又维护了pre、next、item三个属性,其中通过pre指向前一个节点,通过next指向后一个节点,最终实现双向链表
    4. LinkedList的元素的添加和删除不是通过数组完成的,相对来说效率较高

ArrayList和LinkedList比较

底层结构增删效率查改的效率
ArrayList可变数组较低(数组扩容)较高
LinkedList双向链表较高(链表追加)较低
  • 一般来说,在程序中,80%-90%都是查询,因此大部分情况下选择ArrayList

Set接口

  • Set接口基本介绍
    1. 添加和取出顺序不一致,没有索引
    2. 不允许重复元素,所以最多有一个null

Set接口实现子类

HashSet

  • HashSet底层是HashMap,第一次添加时,table数组扩容到16,每当数组元素达到临界值就进行扩容(数组大小乘以2),临界值是数组当前大小*加载因子(默认为0.75)
  • 在java8中,如果一条链表元素到达TREEIFY_THRESHOLD(默认为8)并且table的大小>=MIN_TREEIFY_CAPACITY(默认为64)就进行树化(红黑树),否则扩容
  • 不能有重复元素/对象,可以存放null

LinkedHashSet

  • LinkedHashSet继承了HashSet,是HashSet的子类
  • LinkedHashSet底层是一个LinkedHashMap,底层维护了一个数组table+双向链表
  • LinkedHashSet根据元素的hashCode值决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的
  • 不允许添加重复元素

TreeSet

  1. 使用无参构造器时取出无序
  2. 可以使用有参构造器传入一个比较器来自定义排序规则,该比较器在进行添加操作时被调用
  3. 比较器返回结果为0时不进行添加操作
public static void main(String[] args) {
    //当使用无参时,取出无序
    //TreeSet treeSet = new TreeSet();

    //使用有参时可以传入一个比较器(匿名内部类)并自定义排序规则
    TreeSet treeSet = new TreeSet(new Comparator() {//在进行添加操作时被调用
        @Override
        public int compare(Object o1, Object o2) {//定义比较规则
            //return ((String) o1).compareTo((String) o2);//按字符串从小到大排序
            return ((String) o1).length() - ((String)o2).length();//按字符串长度排序
        }
    });
    //注意:compare返回结果为0时则不进行添加操作

    treeSet.add("jack");
    treeSet.add("tom");
    treeSet.add("a");
    treeSet.add("2");

    System.out.println("treeSet = " + treeSet);
}

Map接口

jdk1.8

  • 特点

    1. Map用于保存具有映射关系的数据:key-value
    2. Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
    3. Map中的key不允许重复,若出现重复则会替换之前的值;Map中的value可以重复
    4. Map中的key和value可以为null,为null的key只能有一个
    5. 常用String类作为Map的key
    6. 一对k-v是放在一个HashMap$Node中的,Node实现了Entry接口
  • 常用方法

    1. put:添加
    2. remove:根据键删除映射关系
    3. get:根据键取值
    4. size:获取元素个数
    5. isEmpty:判断是否为空
    6. clear:清除键值对
    7. containsKey:查找键是否存在
    8. keySet:获取所有键
    9. entrySet:获取所有关系k-v
    10. values:获取所有值
    public static void main(String[] args) {
            Map map = new HashMap();
            map.put("n1","jack");
            map.put("n2","jack");
            map.put("n3","tom");
            map.put(null,"lucy");
            map.put("n4","joe");
    
            System.out.println("map=" + map);
    
            map.remove("n2");
            System.out.println("map=" + map);
    
            Object val = map.get("n1");
            System.out.println("val=" + val);
            
        }
    
  • 遍历方法

    public static void main(String[] args) {
            Map map = new HashMap();
            map.put("n1","jack");
            map.put("n2","jack");
            map.put("n3","tom");
            map.put(null,"lucy");
            map.put("n4","joe");
    
            //第一组:先取出所有key,再根据key取出对应的value
            Set keySet = map.keySet();
            //1.增强for
            System.out.println("-----1-----");
            for (Object key :keySet) {
                System.out.println(key + "-" + map.get(key));
            }
            //2.迭代器
            System.out.println("-----2-----");
            Iterator iterator = keySet.iterator();
            while (iterator.hasNext()) {
                Object key =  iterator.next();
                System.out.println(key + "-" + map.get(key));
            }
    
            //第二组:把所有value取出
            Collection values = map.values();
            //可用collection使用的遍历方法
    
            //第三组:通过EntrySet获取k-v
            Set entrySet = map.entrySet();//EntrySet<Entry<K,V>>
            //1.增强for
            System.out.println("-----3-----");
            for (Object entry :entrySet) {
                //将entry转成Map.Entry
                Map.Entry m= (Map.Entry) entry;
                System.out.println(m.getKey() + "-" + m.getValue());
    
            }
            //2.迭代器
            System.out.println("-----4-----");
            Iterator iterator1 = entrySet.iterator();
            while (iterator1.hasNext()) {
                Object next =  iterator1.next();//next实现类型为HashMap$Node
                //向下转型
                Map.Entry m = (Map.Entry) next;
                System.out.println(m.getKey() + "-" + m.getValue());
            }
    

Map接口实现子类

Map接口常用实现类:HashMap、Hashtable和properties

HashMap

  • 特点

    1. HashMap以 key-value 对的方式来存储数据(HashMap$Node类型)
    2. key不能重复,值可以重复,key和value均可使用null
    3. 如果添加相同的key则会覆盖原来的键值对
    4. 不保证映射顺序,因为底层是以hash表的方式来存储的
    5. HashMap没有实现同步,因此线程不安全
    6. table数组中的节点HashMap N o d e 实 现 了 M a p Node实现了Map NodeMapEntry<K,V>
  • 扩容机制

    1. HashMap底层维护了Node类型的数组table,默认为null
    2. 当创建对象时,将加载因子(loadfactor)初始化为0.75
    3. 当添加k-v时,通过key的哈希值得到再table的索引,然后判断该索引处是否有元素,如果没有直接添加。若该索引处有元素,继续判断该元素的key是否和准备加入的元素的key相等,如果相等则直接替换val。如果不相等则判断是树结构还是链表结构再进行添加;如果添加时发现容量不够则需要扩容
    4. 第1次添加时扩容table容量为16,临界值(threshold)为12,计算方法为当前容量乘以加载因子;以后再扩容时需要扩容table容量为原来的2倍
    5. Java8中,如果一条链表元素超过TREEIFY_THRESHOLD(默认为8)并且table的大小>=MIN_TREEIFY_CAPACITY(默认为64)就进行树化(红黑树),否则扩容

Hashtable

  • 特点
    1. 存放的元素是键值对
    2. hashtable的键和值都不能为null
    3. 线程安全
    4. 数组初始化大小为11

properties

  • 特点

    1. 继承Hashtable并实现了Map接口
  • 常用方法

    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.put("jack",10);
        properties.put("tom",11);
        properties.put("lucy",12);
        properties.put("jerry",13);
        System.out.println("properties = " + properties);
    
        //通过k获取值
        System.out.println(properties.get("jack"));
        System.out.println(properties.getProperty("tom"));
    
        //删除
        properties.remove("jack");
        System.out.println("properties = " + properties);
    
        //修改
        properties.put("tom",50);
        System.out.println("properties = " + properties);
    }
    

TreeMap

与TreeSet类似

  1. 使用无参构造器时取出无序
  2. 可以使用有参构造器传入一个比较器来自定义比较规则(或排序规则),该比较器在进行添加操作时被调用
  3. 比较器返回结果为0时不进行添加操作而不是替换
public static void main(String[] args) {
    //使用无参构造器创建TreeMap是无序的(也没有排序)
    //TreeMap treeMap = new TreeMap();

    TreeMap treeMap = new TreeMap(new Comparator() {
        @Override
        public int compare(Object o1, Object o2) {
            return ((String) o1).compareTo((String) o2);//按k(String)大小排序
        }
    });
    treeMap.put("jack","杰克");
    treeMap.put("tom","汤姆");
    treeMap.put("lucy","露西");
    treeMap.put("smith","斯密斯");

    System.out.println("treemap=" + treeMap);
}

集合选型规则

  1. 先判断存储的类型
  2. 若是一组对象(单列):Collection接口
    • 允许重复:List
      • 增删多:LinkedList(底层维护了一个双向链表)
      • 改查多:ArrayList(底层维护了Object类型的可变数组)
    • 不允许重复:Set
      • 无序:HashSet(底层是HashMap,维护了一个哈希表)
      • 排序:TreeSet
      • 插入和取出顺序一致:LinkedHashSet(维护数组+双向链表)
  3. 若是一组键值对:Map
    • 键无序:HashMap(底层是哈希表)
    • 键排序:TreeMap
    • 键插入和取出顺序一致:LinkedHashMap
    • 读取文件:Properties

Collections工具类

  • Collections工具类介绍

    1. Collections是一个操作Set、List和Map等集合的工具类
    2. Collections中提供了一系列静态方法对集合元素进行排序、查询和修改等操作
  • 排序操作(均为static方法)

    1. reverse(List):反转List中元素的顺序
    2. shuffle(List):对List集合元素进行随机排序
    3. sort(List):根据元素的自然顺序对List集合元素按升序排序
    4. sort(List,Comparator):根据Comparator产生的顺序对List集合元素进行排序
    5. swap(List,int,int):将List集合中两处元素进行交换
  • 查找、替换操作

    1. max(Collection):根据元素的自然顺序返回集合中的最大元素
    2. max(Collection,Comparator):根据比较器指定的顺序返回集合中最大的元素
    3. min(Collection):根据元素的自然顺序返回集合中的最小元素
    4. min(Collection,Comparator):根据比较器指定的顺序返回集合中最小的元素
    5. frequency(Collection,Object):返回集合中指定元素的出现次数
    6. copy(List dest,List src):将src中的内容复制到dest中,两个数组大小需一致
    7. replaceAll(List list,Object oldVal,Object newVal):使用新值替换List对象的所有旧值
public static void main(String[] args) {
    ArrayList list = new ArrayList();
    list.add("jack");
    list.add("tom");
    list.add("lucy");
    list.add("smith");

    Collections.reverse(list);
    System.out.println("反转");
    System.out.println("list = " + list);

    Collections.shuffle(list);
    System.out.println("随机排序");
    System.out.println("list = " + list);

    Collections.sort(list);
    System.out.println("自然排序后");
    System.out.println("list = " + list);

    Collections.sort(list, new Comparator() {
        @Override
        public int compare(Object o1, Object o2) {
            return ((String)o1).length() - ((String)o2).length();
        }
    });
    System.out.println("按字符串长度大小排序");
    System.out.println("list = " + list);

    Collections.swap(list,0,1);
    System.out.println("交换元素位置");
    System.out.println("list = " + list);

    System.out.println("最大元素:" + Collections.max(list));

    ArrayList dest = new ArrayList();
    for (int i =0; i < list.size(); i++){
        dest.add("");
    }//拷贝前需先将目的数组大小与源数组大小一致,否则会抛出异常
    Collections.copy(dest,list);
    System.out.println("dest = " + dest);
    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值