Java学习笔记(六):集合List接口,Set接口,Map接口,Collections工具类

集合

集合与数组

定义:集合与数组都是对多个数据进行存储操作的结构,简称Java容器

数组存储的特点:一旦初始化以后,其长度就确定了;数组一旦定义好,其元素的类型也确定了

数组存储的缺点:长度不可修改;数组中提供的方法很有限

集合的分类

  • 集合框架
    • Collection接口:单列集合,用来存储一个一个的对象
      • List接口:存储有序,可重复的数据(类似“动态”数组)–ArrayList、LinkedList、Vector
      • Set接口:存储无序,不可重复的数据(类似高中“集合”)–HashSet、LinkedHashSet、TreeSet
    • Map接口

Collection接口

遍历Collection元素的方法:

1. 迭代器接口:Iterator
public void test(){
    
    
  Collection collection = new ArrayList();
  collection.add(123456);
  Iterator iterator = collection.iterator();
  // 判断是否还有下一个元素
  while (iterator.hasNext()){
    
    
    System.out.println(iterator.next());
  }
}
2. foreach(内部仍然调用了迭代器)
//for(集合元素类型 局部变量:集合对象)
for(Object obj:collection){
    
    
  System.out.println(obj);
}

Collection子接口:List

存储有序的,可重复的数据

  • ArrayList:List接口的主要实现类,线程不安全,效率高;底层使用Object[] elementData存储
  • LinkedList:对于频繁地插入删除操作,使用此类的效率比ArrayList高,底层使用双向链表存储
  • Vector:List接口的古老实现类,线程安全,效率低,底层使用Object[] elementData存储

常用方法:

增:add(Object obj)

删:remove(int index)/remove(Object obj)

改:set(int index,Object element)

查:get(int index)

插:add(int index, Object element)

长度:size()

遍历:Iterator迭代器、foreach、普通循环

存储元素的要求:添加的对象,所在的类要重写equals()方法

Collection子接口:Set

存储无序的,不可重复的数据

以HashSet为例

无序性:不等于随机性,存储的数据在底层数组中并非按照索引的顺序添加,而是根据数据的哈希值确定的

不可重复性:保证添加的元素按照equals()判断时,不能返回true,即相同的元素只能添加一个

元素添加过程:

  • 1.向HashSet中添加元素a,首先调用元素a所在类的hashcode(),计算a的哈希值,此哈希值接着通过某种算法计算出HashSet底层数组中的存放位置
  • 2.判断数组此位置上是否已有元素
    • 2.1 没有元素,则元素a添加成功(情况一)
    • 2.2 有元素b,则比较元素a和元素b的哈希值
      • 2.2.1 如果hash值不同,则a添加成功(情况二)
      • 2.2.2 如果hash值相同,调用a所在类的equals()
        • 2.2.2.1 equals()返回true,a添加失败
        • 2.2.2.2 equals()返回false,a添加成功(情况三)

情况二和情况三:

jdk7:元素a放到数组中,指向原来的元素

jdk8:原来的元素在数组中不变,指向a

HashSet底层:数组+链表(jdk7)

分类:

  • HashSet:Set接口的主要实现类,线程不安全的,可以存储null值
  • LinkedHashSet:HashSet的子类
    • 遍历其内部数据时,可以按照添加的顺序遍历(因为在添加数据的同时,每个数据会维护两个引用,分别记录前后的两个数据)
    • 对于频繁的遍历操作,LinkedHashSet效率高于HashSet
  • TreeSet:可以按照添加对象的指定属性,进行排序。底层是红黑树,与排序相关,应用到Comparable

存储对象所在类的要求:

HashSet/LinkedHashSet:向Set中添加的数据,其所在的类一定要重写hashCode()和equals()

Map接口

双列数据,存储key-value对的数据

分类:

  • HashMap:Map的主要实现类,线程不安全,效率高,可以存储null的key,value
  • LinkedHashMap:HashMap的子类。
    • 保证在遍历map元素时,可以按照添加的顺序实现遍历(因为在原HashMap的基础上,添加了一对指针,指向前一个元素和后一个元素)
    • 对于频繁的遍历操作,效率高于HashMap
  • TreeMap:保证按照添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序,底层使用红黑树
  • HashTable:古老的Map实现类,线程安全,效率低,不能存储null的key或value
  • Properties:HashTable子类,常用来处理配置文件。key和value都是String类型

HashMap的底层:

数组+链表(jdk7)

数组+链表+红黑树(jdk8)

HashMap的实现原理

一、在jdk7中的实现原理

HashMap map = new HashMap();

在实例化以后,底层创建了长度为16的一维数组Entry[] table

map.put(key1,value1);

Map.put(key2,value2);…

首先调用key1所在类的hashCode()计算key1的hash值,此hash值经过某种算法计算以后,得到在Entry[]中的存放位置

  • 1 如果此位置上的数据为空,则key1-value1添加成功
  • 2 如果此位置上的数据不为空,则比较key1与其他数据的hash值
    • 2.1 key1的hash值与其他数据的hash值不同,则添加成功
    • 2.2 key1的hash值与其他数据的hash值相同,则继续比较equals()
      • 2.2.1 返回false,key1-value1添加成功
      • 2.2.2 返回true,value1替换value x

二、HashMap在jdk8相比于jdk7的不同

  • new HashMap():底层没有创建长度为16的数组
  • jdk8底层的数组是:Node[],而不是Entry[]
  • 首次调用put(),底层创建长度为16的数组
  • 七上八下

Collections工具类

作用:操作Collection和Map的工具类

常用方法:

  • reverse(List)
  • shuffle(List):对List集合元素进行随机排序
  • sort(List)
  • swap(Listing,int)

说明:ArrayList和HashMap线程不安全,我们可以使用synchronizedList(List list)和synchronizedMap(Map map)

猜你喜欢

转载自blog.csdn.net/qq_40177015/article/details/114445317