JavaSE-集合总结


1. Collection

  1. Collection是所有单列集合的父接口,在Collection中定义了单列集合(List和Set)通用的一些方法,而且Collection重写了toString。

  2. Collection接口常用方法:

    // 把给定的对象添加到当前集合中
    public boolean add(E e);
    
    // 清空集合中所有的元素
    public void clear();
    
    // 把给定的对象在当前集合中删除
    // 若有相同元素,只删除遇到的第一个
    public boolean remove(E e);
    
    // 判断当前集合中是否包含给定的对象
    public boolean contains(E e);
    
    // 判断当前集合是否为空
    public boolean isEmpty();
    
    // 返回集合中元素的个数
    public int size();
    
    // 把集合中的元素,存储到数组中
    public Object[] toArray();
    
    // 返回在此 collection 的元素上进行迭代的迭代器
    Iterator<E> iterator()
    

Iterator接口

  1. 想要遍历Collection集合,那么就要获取该集合迭代器完成迭代操作。

  2. Iterator接口的常用方法:

    // 返回迭代的下一个元素
    public E next()
    
    // 如果仍有元素可以迭代,则返回true
    public boolean hasNext()
    
    // 从迭代器指向的collection中移除迭代器返回的最后一个元素
    // 该方法会在删除当前元素的同时维护索引的一致性
    void remove()
    
  3. Iterator迭代器遍历集合时,不能使用集合的方法对集合进行增删操作,不然会有并发修改异常;但可以使用Iterator本身的remove()方法来删除元素

  4. ListIterator:允许沿任一方向遍历列表,在迭代期间修改集合,并获取列表中迭代器的当前位置。

    // 将指定的元素插入列表
    void add(E e)
    
    // 从列表中删除next()或previous()返回的最后一个元素
    void remove()
    
    // 用指定的元素替换next()或previous()返回的最后一个元素
    void set(E e)
    
    // 如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回 true
    boolean hasPrevious()
    
    // 返回列表中的上一个元素,并向后移动光标位置
    E previous()
    

增强for

  • 增强for循环(也称for each循环)是JDK1.5以后出来的一个高级for循环,实现Iterable接口的对象,都可以使用增强for。增强for专门用来遍历数组和Collection集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作。

    for (元素类型 变量名 : 数组名或集合对象) {
    }
    

1.1 List接口

  1. List接口特点:元素存取有序、有索引、元素可重复

  2. List接口常用方法:

    // 将指定的元素,添加到该集合中的指定位置上
    public void add(int index, E element)
    
    // 返回集合中指定位置的元素
    public E get(int index)
    
    // 移除列表中指定位置的元素, 返回的是被移除的元素
    public E remove(int index)
    
    // 用指定元素替换集合中指定位置的元素,返回值的更新前的元素
    public E set(int index, E element)
    
1.1.1 ArrayList集合
  1. ArrayList数据存储的结构是数组,增删慢,查找快。

  2. ArrayList索引从0开始,默认初始容量为10,每次扩容为:原始长度的1.5倍(原始长度+原始长度>>1)

  3. 创建ArrayList对象实例:

    // 从JDK1.7+开始,右侧<>里面可以不写内容,但<>本身要写
    // 建议右侧<>中写上类型
    ArrayList<String> arrayList = new ArrayList<>();
    
1.1.2 LinkedList集合
  1. LinkedList数据存储的结构是双向链表,增删快,查找慢。

  2. 可以作为堆栈,队列的结构使用

  3. 有自己的特有方法,所以最好不要使用多态

    // 将指定元素插入此列表的开头
    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)
    
1.1.3 CopyOnWriteArrayList
  • CopyOnWriteArrayList是ArrayList的一个线程安全的变体

1.2 Set接口

  1. Set接口特点:元素存取无序、无索引、不可重复
  2. Set没有带索引的方法,所以不能使用普通for循环遍历。取出元素可以采用:迭代器、增强for。
1.2.1 HashSet集合
  1. HashSet数据存储的结构是哈希表,查询速度非常快。
  2. 哈希表:在JDK1.8之前,哈希表底层采用数组+单链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过**阈值(8)**时,将链表转换为红黑树,这样大大减少了查找时间。
  3. 哈希表初始数组容量为16,加载因子默认为0.75,不过也可以在构造时传递(不建议)。
  4. HashSet底层的实现是一个HashMap支持。HashSet本身没什么功能,依靠HashMap来实现功能。
  5. HashSet根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。
  6. HashSet保证数据唯一的原理:HashSet在添加元素时,首先会判断集合中是否有与该元素哈希值相同的元素;如果哈希值都不同,就根据哈希值将该元素直接添加到对应的数组索引处;如果哈希值相同,就执行equals依次与哈希值对应的数组索引处的链表元素比较;如果equals比较相等,会用新元素替换原有元素。
  7. 给HashSet中存放自定义类型元素时,需要覆盖重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一。
1.2.2 LinkedHashSet集合
  • LinkedHashSet,它是链表和哈希表组合的一个数据存储结构,由链表保证元素存取有序。底层是哈希表,但与父类不同的是LinkedHashSet采用双向链表。
1.2.3 TreeSet集合
  • 元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法

    // 根据其元素的自然排序进行排序
    TreeSet()
    // 根据指定的比较器进行排序
    TreeSet(Comparator comparator)
    
1.2.4 CopyOnWriteArraySet
  • CopyOnWriteArraySet是一个对其所有操作使用内部的CopyOnWriteArrayList的Set

1.3 JDK9的of()方法

  1. of()只是List、Set、Map这三个接口的静态方法,其父类接口和子类实现并没有这类方法。
  2. of()返回的是一个不能改变的集合,该集合不能再使用add、put方法添加元素。
  3. Set和Map在调用of()时,不能有重复的元素。

1.4 Collections

  • Collections是Collection集合的工具类,其常用方法有:

    // 将所有指定的元素添加到指定的集合
    static <T> boolean addAll(Collection<? super T> c, T... elements)
    
    // 反转指定列表中元素的顺序
    static void reverse(List<?> list)
    
    // 使用默认的随机源随机排列指定的列表
    static void shuffle(List<?> list)
    
    // 根据其元素的自然顺序按照升序排列指定的列表
    static <T extends Comparable<? super T>> void sort(List<T> list)
    
    // 根据指定的比较器引起的顺序对指定的列表进行排序
    static <T> void sort(List<T> list, Comparator<? super T> c)
    
    // 返回由指定集合支持的同步(线程安全)集合
    static <T> Collection<T> synchronizedCollection(Collection<T> c)
    
    // 返回由指定列表支持的同步(线程安全)列表
    static <T> List<T> synchronizedList(List<T> list)
    
    // 返回由指定集合支持的同步(线程安全)集
    static <T> Set<T> synchronizedSet(Set<T> s)
    
    // 返回由指定地图支持的同步(线程安全)映射
    static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
    
  • sort排序自定义对象:

    传递Comparator实现类:
    // 比较其两个参数的顺序
    // 升序:返回o1 - o2
    // 降序:返回o2 - o1
    // 相等情况:o1 - o2 = 0
    public int compare(T o1, T o2)
    
    本身实现Comparable接口:
    // 升序:返回o - this
    // 降序:返回this - o
    public int compareTo(T o)
    

2. Map

  1. Map接口专门用来存放映射关系的对象

  2. Map中的元素是成对存在的,每个元素由键与值两部分组成,通过键可以找对所对应的值。键不能重复,值可以重复,且每个键只能对应一个值

  3. HashMap<K,V>:存储数据采用的哈希表结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需要重写键的hashCode()和equals()。

  4. LinkedHashMap<K,V>:存储数据采用的哈希表结构+链表结构,通过链表结构可以保证元素的存取顺序一致;通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()和equals()。

  5. TreeMap<K,V>:构造时可以传递Comparator实现类,以按照指定规则对键进行排序

  6. HashTable:

    1. 使用synchronized来保证线程安全
    2. 一个操作正在进行时,其他所有操作也同时锁定
    3. 锁定整个哈希表,效率相对较低
  7. ConcurrentHashMap<K,V>:

    1. 使用CAS机制来保证线程安全
    2. 支持遍历过程中增删元素
    3. 不允许将null用作键或值
    4. 某些功能不锁定(如get)
    5. 当添加或者移除元素时,是对链表进行操作,而链表存储在数组中,那么就只会针对这个链表进行锁定(局部锁定),效率相对较高
  8. HashMap和HashTable的区别:HashMap是JDK1.2出现的,线程不同步,键和值可以为null;HashTable是JDK1.0出现的,线程同步,键和值不可以为null。

  9. Map接口常用方法:

    // 把指定的键与指定的值添加到Map集合中
    // 若指定的键(key)在集合中没有,则没有这个键对应的值,返回null,并把指定的键值添加到集合中
    // 若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值
    public V put(K key, V value)
    
    // 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值
    public V remove(Object key)
    
    // 判断集合中是否包含指定的键
    boolean containsKey(Object key)
    
    // 判断集合中是否包含指定的值
    boolean containsValue(Object value)
    
    // 根据指定的键,在Map集合中获取对应的值
    public V get(Object key)
    
    // 获取Map集合中所有值的集合
    Collection<V> values()
    
    // 获取Map集合中所有的键,存储到Set集合中
    public Set<K> keySet()
    
    // 获取到Map集合中所有的键值对对象的集合(Set集合)
    public Set<Map.Entry<K,V>> entrySet()
    
  10. Entry键值对:Map中存放的是两种对象:key(键)、value(值),这一对对象又称做Map中的一个Entry(项)。Entry将键值对的对应关系封装成了对象。

    Entry对象获取对应键和对应值的方法:
    // 获取Entry对象中的键
    public K getKey()
    
    // 获取Entry对象中的值
    public V getValue()
    
  11. Map不能使用迭代器或者foreach进行遍历

  12. Map遍历键找值:

    1. 获取Map中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键。keyset()
    2. 遍历键的Set集合,得到每一个键。
    3. 根据键,获取键所对应的值。get(K key)
  13. Map遍历键值对:

    1. 获取Map集合中,所有的键值对(Entry)对象,以Set集合形式返回。entrySet()
    2. 遍历包含键值对(Entry)对象的Set集合,得到每一个键值对(Entry)对象。
    3. 通过键值对(Entry)对象,获取Entry对象中的键与值。getkey()、getValue()

2.1 Properties

  • Properties继承于Hashtable,是Map的一个实现类,表示一个持久的属性集。Properties每个键及其对应值的类型都被固定为字符串。

    构造方法:
    // 创建一个空的属性列表
    public Properties()
    
    Properties作为集合的特有方法:
    // 保存一对属性
    public Object setProperty(String key, String value)
    
    // 使用此属性列表中指定的键搜索属性值
    public String getProperty(String key)
    
    // 所有键的名称的集合,相当于keySet()方法
    public Set<String> stringPropertyNames()
    
    Properties和IO流结合的方法:
    // 从字节输入流中读取键值对
    public void load(InputStream inStream)
    
    // 以简单的线性格式从输入字符流读取属性列表(关键字和元素对)
    void load(Reader reader)
    
    // 将此属性列表(键和元素对)写入此Properties表中,以适合于使用load(InputStream)方法的格式写入输出字节流
    void store(OutputStream out, String comments)
    
    // 将此属性列表(键和元素对)写入此Properties表中,以适合使用load(Reader)方法的格式输出到输出字符流
    void store(Writer writer, String comments)
    
    参数中使用了字节输入流,通过流对象可以关联到某文件上,这样就能够加载文本中的数据了。
    文本数据格式:变量名=值
    文本中的数据,必须是键值对形式,可以使用空格、等号、冒号等符号分隔
    #是注释
    
    java.util.ResourceBundle类可以读取properties文件:
    // 获取一个ResourceBundle;baseName不需要加文件后缀名
    static ResourceBundle getBundle(String baseName)
    // 获取指定key的值
    String getString(String key)
    

3. 泛型

  1. 泛型好处:将运行期异常提升到了编译期。如:创建集合时不写泛型,则可以存储任意引用类型数据,这样在运行时可能会出错;写了泛型就会在编译时期,检测集合中的数据类型,如果和泛型不一致就会编译失败。

  2. 泛型不存在继承关系

    // 错误示例
    Collection<Object> list = new ArrayList<String>();
    
  3. 泛型的通配符:当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。此时只能接收数据,不能往该集合中存储数据(也就是只能作为方法的参数传递)。

  4. 静态方法的泛型不能和类上的泛型相同,因为静态不能直接访问非静态,类上的泛型在new对象时才指定。

  5. JAVA的泛型中可以指定一个泛型的上限和下限

    // 定义含有泛型的类
    // 创建对象时确定泛型
    修饰符 class 类名<代表泛型的变量> {
    }
    
    // 定义含有泛型的接口
    // 1. 实现接口时确定泛型
    // 2. 始终不确定泛型,直到创建实现类对象时,确定泛型***
    修饰符 interface 接口名<代表泛型的变量> {
    }
    
    // 定义含有泛型的方法
    // 调用方法时确定泛型
    修饰符 <代表泛型的变量> 返回值类型 方法名(参数列表) {
    }
    
    // 泛型通配符和迭代器的使用
    public static void printArrayList(ArrayList<?> arrayList) {
        Iterator<?> it = arrayList.iterator();
        while (it.hasNext()) {
            Object next = it.next();
            System.out.println(next);
        }
    }
    
    泛型的上限:
    	格式:类型名称<? extends> 对象名称
    	意义:只能接收该类型及其子类
    
    泛型的下限:
    	格式:类型名称<? super> 对象名称
    	意义:只能接收该类型及其父类型
    

4. 可变参数…

  1. JDK1.5之后,如果定义一个方法需要接受多个参数,并且多个参数类型一致,可以对其简化成如下格式:

    // 调用时直接传递数据即可
    修饰符 返回值类型 方法名(参数类型... 形参名){
    }
    
    // 完全等价于上面,但调用时必须传递数组
    修饰符 返回值类型 方法名(参数类型[] 形参名){
    }
    
  2. 调用带有可变参数的方法时,不用创建数组(这就是简单之处),直接将数组中的元素作为实际参数进行传递。其实编译成的class文件,将这些元素先封装到一个数组中,再进行传递,这些动作都在编译.class文件时自动完成了。

  3. 一个方法的参数列表只能有一个可变参数,并且可变参数一定要写在参数列表的末尾位置。

若有错误或补充,欢迎私信

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值