常用集合类

一、Collection类

集合:Java中提供的一种容器,可以用来存储多个引用类型的数据。

集合与数组的区别:

  1. 数组的长度是固定的,而集合的长度是可变的。
  2. 集合存储的都是引用数据类型,若想存储基本数据类型需要存储对应的包装类。

1. 概述

1.1 简介

Collection单列集合类的根接口,用于存储一些列符合某种规则的元素,其有两个常用的子接口:

  1. java.util.List:元素存取有序、有索引、且可重复,主要的实现类:

    java.util.ArrayList 查询快、增删慢

    java.util.LinkedList 查询慢、增删快

  2. java.util.Set: 元素无索引、且不可重复,主要实现类:

    java.util.HashSet 存取无序

    java.util.LinkedHashSet 存取有序

    java.util.TreeSet 可以对集合中的元素进行排序
    在这里插入图片描述

1.2 常用方法

Collection是所有单列集合的父接口,因此在Collection中定义了一些单列集合通用的方法,这些方法可用于操作所有单列集合。

public boolean add(E e); 				把给定的对象添加到当前集合中 。
public void clear();					清空集合中所有的元素。
public boolean remove(E e); 			把给定的对象在当前集合中删除。
public boolean contains(Object obj); 	判断当前集合中是否包含给定的对象。
public boolean isEmpty();				判断当前集合是否为空。
public int size();						返回集合中元素的个数。
public Object[] toArray();				把集合中的元素,存储到数组中

2. 迭代器

2.1 使用

迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续再判断,如果还有就再取出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。

常用方法

public Iterator iterator();	//获取迭代器对象
public E next();			//返回迭代的下一个元素
public boolean hasNext()	//如果仍有元素可以迭代,则返回 true。

使用方式

当遍历集合时,首先通过调用t集合的iterator()方法获得迭代器对象,然后使用hashNext()方法判断集合中是否存在下一个元素,如果存在,则调用next()方法将元素取出,否则说明已到达了集合末尾,停止遍历元素。

常见问题

  1. 若集合中已无元素可迭代时,仍使用迭代器的next()方法,将会抛出java.util.NoSuchElementException异常,若想重新迭代就需要重新获取一个新的迭代器。
  2. 在进行集合元素迭代时,若添加/移除集合中的元素,将导致无法继续迭代,抛出ConcurrentModificationException异常。

原理

iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素。

  1. 在调用Iteratornext()方法之前,迭代器的索引位于第一个元素之前,不指向任何元素
  2. 当第一次调用迭代器的next()方法后,迭代器的索引会向后移动一位,指向第一个元素并将该元素返回,当再次调用next()方法时,迭代器的索引会指向第二个元素并将该元素返回
  3. 依此类推,直到hasNext()方法返回false,表示到达了集合的末尾,终止对元素的遍历。

2.2 增强for循环

增强for循环专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作,否则会抛出ConcurrentModificationException异常。

public class JavaTest {
    public static void main(String[] args) {
        Collection<String> strings = new ArrayList<String>();	//构造集合
        strings.add("abc");	//添加元素
        strings.add("cba");
        strings.add("nba");
        strings.add("def");
        
        for (String str:strings) {	//高级for循环遍历集合元素
            System.out.println(str);
        }
        
        Iterator<String> iterator = strings.iterator();	//创建迭代器对象
        while (iterator.hasNext()) {	//判断是否可以继续迭代
            System.out.println(iterator.next());	//获取下一个元素
            if (strings.contains("nba")) {	//判断是否包含指定元素
                strings.remove("nba");	//删除指定的元素
            }	//报java.util.ConcurrentModificationException异常
        }
    }
}

二、Collections类

java.utils.Collections是集合工具类,其成员方法都是静态方法,用来对collection进行操作。

1. 排序

1.1 常用方法

public static void shuffle(List<?> list);	//打乱集合顺序。
public static <T> void sort(List<T> list);	//将集合中元素按照默认规则排序。
public static <T> void sort(List<T> list,Comparator<?superT>);//将集合中元素按照指定规则排序。

1.2 默认规则排序

  1. collection元素的类需要继承Compareable接口,并重写compareTo()方法。this - 参数为升序,反之则为降序
  2. 创建Collection集合并添加要排序类的元素
  3. 调用Collections.sort()方法即可对Collection中的元素排序

class Cls implements Comparable<Cls>{	//实现Compareable接口
    private int age;
    public Cls(int age) {
        this.age = age;
    }

    @Override
    public int compareTo(Cls c) {
        return this.age - c.age;
    }
    @Override
    public String toString() {
        return age + "  ";
    }
}
public class JavaTest {
    public static void main(String[] args) {
        Cls c1 = new Cls(10);
        Cls c2 = new Cls(20);
        Cls c3 = new Cls(30);
        Cls c4 = new Cls(40);

        ArrayList<Cls> cls = new ArrayList<>();
        cls.add(c1);
        cls.add(c3);
        cls.add(c4);
        cls.add(c2);

        Collections.sort(cls);
        System.out.println(cls);	//[10  , 20  , 30  , 40  ]
    }
}

1.3 自定义规则排序

直接调用 Collections.sort()方法,传入要排序的集合和Comparator的匿名内部类(内部重写了compare()方法)

class Cls{
    public int age;
    public Cls(int age) {
        this.age = age;
    }
}
public class JavaTest {
    public static void main(String[] args) {
        Cls c1 = new Cls(10);
        Cls c2 = new Cls(20);
        Cls c3 = new Cls(30);
        Cls c4 = new Cls(40);

        ArrayList<Cls> cls = new ArrayList<>();
        cls.add(c1);
        cls.add(c3);
        cls.add(c4);
        cls.add(c2);

        Collections.sort(cls, new Comparator<Cls>() {	//匿名内部类
            @Override
            public int compare(Cls o1, Cls o2) {
                return o2.getAge() - o1.getAge();
            }
        });
    }
}

2. 可变参数

作用:JDK1.5之后,如果定义一个方法需要接收多个同类型参数,可以使用可变参数进行简化,当传入多个参数时,相当于传入了一个数组。

  1. 一个方法只能有一个可变参数
  2. 如果方法中有多个参数,可变参数要放到最后。
class Cls{
    public String name;
    public void method(int age, String... name) {	//可变参数
        for (String str:name) {
            System.out.println(str);	//遍历传入的数据
        }
    }
}
public class JavaTest {
    public static void main(String[] args) {
        Cls cls = new Cls();
        cls.method(10, "a", "b", "c");
		//可以一次性向集合中添加多个,而不需要逐个添加
        ArrayList<String> strings = new ArrayList<>();
        Collections.addAll(strings, "a", "b", "c");
    }
}

三、List接口

1. 概述

特点

java.util.List接口继承自Collection接口,是单列集合的一个重要分支,习惯性地会将实现了List接口的对象称为List集合。元素特点是存取有序、带有索引、可重复。

常用方法

List作为Collection集合的子接口,不但继承了Collection接口中的全部方法,还增加了一些独有的方法。

public void add(int index, E element);	//将指定的元素,添加到该集合中的指定位置上。
public E get(int index);			//返回集合中指定位置的元素。
public E remove(int index); 		//移除列表中指定位置的元素, 返回的是被移除的元素。
public E set(int index, E element);	//用指定元素替换集合中指定位置的元素,返回值的更新前的元素。

2. ArrayList集合

java.util.ArrayList集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList是最常用的集合。

常用方法

其内部没有独特的方法,都是实现的Collection接口和List接口的方法

ArrayList();							//构造方法,构造一个初始容量为 10 的空列表。 
ArrayList<E> list1 = new ArrayList<E>();	//构造方法,构造一个E类型的列表

public boolean add(E e);				//想集合尾部插入数据
public void add(int index,E element);	//向指定位置插入数据
public boolean   remove(Object o); 		//删除指定的元素,返回删除是否成功
public E   remove(int   index); 		//删除指定索引处的元素,返回被删除的元素
public E   set(int index, E  element); 	//修改指定索引处的元素,返回被修改的元素
public E   get(int   index); 			//返回指定索引处的元素
public int   size(); 					//返回集合中的元素的个数

3. LinkedList集合

java.util.LinkedList集合数据存储的结构是双向链表。方便元素添加、删除的集合。

常用方法

实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。

public void addFirst(E e);	//将指定元素插入此列表的开头。
public void addLast(E e);	//将指定元素添加到此列表的结尾。
public E getFirst();		//返回此列表的第一个元素。
public E getLast();			//返回此列表的最后一个元素。
public E removeFirst();		//移除并返回此列表的第一个元素。
public E removeLast();		//移除并返回此列表的最后一个元素。
public E pop();				//从此列表所表示的堆栈处弹出一个元素。
public void push(E e);		//将元素推入此列表所表示的堆栈。

四、Set接口

1. 概述

Set接口:也称Set集合,但凡是实现了Set接口的类都叫做Set集合,特点是元素无索引、不可重复(唯一)

  1. Set集合没有特殊的方法,都是使用Collection接口的方法
  2. Set集合没有索引,所以遍历元素的方式就只有: 增强for循环,或者迭代器

2. HashSet集合

2.1 原理

底层数据结构

  1. HashSet集合存储数据的结构是哈希表

    • JDK1.8之前哈希表底层采用数组+链表实现,同一哈希值的链表都存储在一个数组中,但当前链表的元素过多时,通过key遍历查找效率较低
    • JDK1.8及之后哈希表底层采用数组+链表+红黑树,当链表元素长度超过8时,链表会转为红黑树,提高了遍历效率。
      在这里插入图片描述
  2. HashSet集合保证元素唯一时依赖于hashCode()equals()方法

    • 当存储元素时HashSet会调用该元素的hashCode()方法计算其哈希值
    • 判断数组中该哈希值对应的位置上是否有元素,若没有则直接存储;
    • 若有对应位置上有元素则说明产生了哈希冲突,会调用该元素的equals()方法与对应位置上的元素逐一比较
    • 若该位置上有任意元素与该元素相同则不存储,若没有相同则在当前位置的链表/红黑树上添加一个新节点。

源码

HashSet底层是HashMap

public class HashSet<E> extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable{
    private transient HashMap<E,Object> map;
    //构造函数
    public HashSet() {	//实际上内部使用HashMap实现的
        map = new HashMap<>();
    }  
}

2.2 存储自定义类

  1. 重写写该类的hashCode()equals()方法。

    由于HashSet保证元素唯一性是通过hashCode()根据元素地址生成的哈希值和equals()比较元素的地址,因此在存储自定义类的元素时,需要重写该类的hashCode()equals()方法。

    public class Person{
        public String name;
        public int age;
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
        @Override	//重写equals()方法
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Person person = (Person) o;
            return age == person.age &&
                    Objects.equals(name, person.name);
        }
    
        @Override	//重写hashCode()方法
        public int hashCode() {
            return Objects.hash(name, age);
        }
    }
    
  2. 使用方法

    //自定义类
    class CA {
        private String name;
        private int age;
        public CA(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        @Override	//重写equals方法
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            CA ca = (CA) o;
            return age == ca.age &&
                    Objects.equals(name, ca.name);
        }
    
        @Override	//重写hashCode方法
        public int hashCode() {
            return Objects.hash(name, age);
        }
    
        @Override
        public String toString() {
            return name + ": " + age;
        }
    
    }
    public class JavaTest {
        public static void main(String[] args) {
            CA ca0 = new CA("abc", 10);a	//定义自定义类元素
            CA ca1 = new CA("123", 11);
            CA ca2 = new CA("abe", 12);
            CA ca3 = new CA("abc", 10);
            HashSet<CA> cas = new HashSet<>();	//创建HashSet集合
            cas.add(ca0);	//添加自定义类对象到HashSet集合
            cas.add(ca1);
            cas.add(ca2);
            cas.add(ca3);
            for (CA ca: cas) {	
                System.out.println(ca.toString());	//abc: 10	//重写了方法,只有一个该元素
    		}										//abe: 12
    	}											//123: 11	//存取无序
     }       
        
    
    
    

3. LinkedHashSet集合

**作用:**在HashSet下面的子类java.util.LinkedHashSet,它是链表和哈希表组合的一个数据存储结构,可以解决HashSet存取无序。

public class Test {
    public static void main(String[] args) {
        LinkedHashSet<Integer> set = new LinkedHashSet<>();// 存取有序
        // 往集合中存储数据
        set.add(300);
        set.add(100);
        set.add(200);
        set.add(500);
        set.add(400);
        set.add(400);

        System.out.println(set);// [300, 100, 200, 500, 400]
    }
}

4. TreeSet集合

TreeSet集合是Set接口的一个实现类,底层依赖于TreeMap,是一种基于红黑树的实现,使用元素的自然新婚徐对元素进行排序,或者根据创建TreeSet 时提供的 Comparator比较器进行排序,具体取决于使用的构造方法:

public TreeSet();								//根据其元素的自然排序进行排序
public TreeSet(Comparator<E> comparator);    	//根据指定的比较器进行排序
class Cls{
    public int age;
}
public class JavaTest {
    public static void main(String[] args) {
        TreeSet<Cls> cls1 = new TreeSet<>(new Comparator<Cls>() {
            @Override
            public int compare(Cls o1, Cls o2) {
                return o1.age - o2.age;
            }
        });
    }
}

五、Map集合

1. 特点

Map<K,V>集合的特点: K用来限制键的类型,V用来限制值的类型

  1. Map集合存储元素是以键值对的形式存储,每一个键值对都有键和值
  2. Map集合的键是唯一,值可以重复,如果键重复了,那么值就会被覆盖

Map集合子类:
- HashMap<K,V>:存储数据采用的哈希表结构,元素的存取无序。
由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。

  • LinkedHashMap<K,V>HashMap下的子类,存储数据采用的哈希表结构+链表结构,元素存取有序。
    通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
  • TreeMap<K,V>TreeMap集合和Map相比没有特有的功能,底层的数据结构是红黑树;
    可以对元素的键进行排序,排序方式有两种:自然排序和比较器排序

具体的使用方法可以参考Set集合子类的方法

2. 常用方法

public V put(K key, V value);         	//添加键值对到Map集合中。
public V remove(Object key);        	//移除指定的键值对,返回被移除的值
public V get(Object key);			 	//根据key,获取value
public boolean containsKey(Object key); //判断该集合中是否包含key
public Set<K> keySet();        			//获取Map集合中所有的键,存储到Set集合中。
public Set<Map.Entry<K,V>> entrySet();  //获取到Map集合中所有的键值对对象的集合(Set集合)。

3. 遍历

遍历可以通过键找值的方式,也可以通过键值对的方式

public class JavaTest {
    public static void main(String[] args) {
        Map<String, Integer> stringIntegerMap = new HashMap<>();
        stringIntegerMap.put("abc", 1);
        stringIntegerMap.put("abd", 2);
        stringIntegerMap.put("abe", 3);
        stringIntegerMap.put("abf", 4);
		
        //通过键找值
        Set<String> strings = stringIntegerMap.keySet();
        for (String string:strings) {
            System.out.println(string + "   " + stringIntegerMap.get(string));
        }
		//直接获取键值对
        Set<Map.Entry<String, Integer>> entries = stringIntegerMap.entrySet();
        for (Map.Entry<String, Integer> entrie : entries) {
            System.out.println(entrie.getKey() +"   "+ entrie.getValue());
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值